office-gobmx/svx/source/svdraw/sdrhittesthelper.cxx
Armin Le Grand d62d07b3d2 Corrected HitTest for layouted text
For text layouted using EditEngine the HitTest in SVX is
identifying Field like URLs. Thus ist is better to use the
anyways more precise primitives for HitTest (rotation/shear/
mirror, ...). This was necessary since the former mechanism
which used a combination of primitive-beased HitTest and then
using an Outliner to get the position/content of the Field
landed on different positions e.g. when the layout needed to
use multiple lines for the contained URL, but there could
be more cases found.
Adapted the text decompositon, the primitive HitTest and
the TextHirearchyFieldPrimitive2D accordingly.

Change-Id: Ice559e20d02547fdcfcf9783e7cc5481706aab03
Reviewed-on: https://gerrit.libreoffice.org/40591
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
2017-07-31 21:26:03 +02:00

175 lines
6 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <svx/sdrhittesthelper.hxx>
#include <svx/obj3d.hxx>
#include <svx/helperhittest3d.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <drawinglayer/processor2d/hittestprocessor2d.hxx>
#include <svx/svdpagv.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/svdmodel.hxx>
// #i101872# new Object HitTest as View-tooling
SdrObject* SdrObjectPrimitiveHit(
const SdrObject& rObject,
const Point& rPnt,
sal_uInt16 nTol,
const SdrPageView& rSdrPageView,
const SdrLayerIDSet* pVisiLayer,
bool bTextOnly,
drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
{
SdrObject* pResult = nullptr;
if(rObject.GetSubList() && rObject.GetSubList()->GetObjCount())
{
// group or scene with content. Single 3D objects also have a
// true == rObject.GetSubList(), but no content
pResult = SdrObjListPrimitiveHit(*rObject.GetSubList(), rPnt, nTol, rSdrPageView, pVisiLayer, bTextOnly);
}
else
{
if( rObject.IsVisible() && (!pVisiLayer || pVisiLayer->IsSet(rObject.GetLayer())))
{
// single object, 3d object, empty scene or empty group. Check if
// it's a single 3D object
const E3dCompoundObject* pE3dCompoundObject = dynamic_cast< const E3dCompoundObject* >(&rObject);
if(pE3dCompoundObject)
{
const basegfx::B2DPoint aHitPosition(rPnt.X(), rPnt.Y());
if(checkHitSingle3DObject(aHitPosition, *pE3dCompoundObject))
{
pResult = const_cast< E3dCompoundObject* >(pE3dCompoundObject);
}
}
else
{
// not a single 3D object; Check in first PageWindow using primitives (only SC
// with split views uses multiple PageWindows nowadays)
if(rSdrPageView.PageWindowCount())
{
const double fLogicTolerance(nTol);
const basegfx::B2DPoint aHitPosition(rPnt.X(), rPnt.Y());
const sdr::contact::ViewObjectContact& rVOC = rObject.GetViewContact().GetViewObjectContact(
rSdrPageView.GetPageWindow(0)->GetObjectContact());
if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly, pHitContainer))
{
pResult = const_cast< SdrObject* >(&rObject);
}
}
}
}
}
return pResult;
}
SdrObject* SdrObjListPrimitiveHit(
const SdrObjList& rList,
const Point& rPnt,
sal_uInt16 nTol,
const SdrPageView& rSdrPageView,
const SdrLayerIDSet* pVisiLayer,
bool bTextOnly)
{
size_t nObjNum(rList.GetObjCount());
SdrObject* pRetval = nullptr;
while(!pRetval && nObjNum > 0)
{
nObjNum--;
SdrObject* pObj = rList.GetObj(nObjNum);
pRetval = SdrObjectPrimitiveHit(*pObj, rPnt, nTol, rSdrPageView, pVisiLayer, bTextOnly);
}
return pRetval;
}
bool ViewObjectContactPrimitiveHit(
const sdr::contact::ViewObjectContact& rVOC,
const basegfx::B2DPoint& rHitPosition,
double fLogicHitTolerance,
bool bTextOnly,
drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
{
basegfx::B2DRange aObjectRange(rVOC.getObjectRange());
if(!aObjectRange.isEmpty())
{
// first do a rough B2DRange based HitTest; do not forget to
// include the HitTolerance if given
if(basegfx::fTools::more(fLogicHitTolerance, 0.0))
{
aObjectRange.grow(fLogicHitTolerance);
}
if(aObjectRange.isInside(rHitPosition))
{
// get primitive sequence
sdr::contact::DisplayInfo aDisplayInfo;
const drawinglayer::primitive2d::Primitive2DContainer& rSequence(rVOC.getPrimitive2DSequence(aDisplayInfo));
if(!rSequence.empty())
{
// create a HitTest processor
const drawinglayer::geometry::ViewInformation2D& rViewInformation2D = rVOC.GetObjectContact().getViewInformation2D();
drawinglayer::processor2d::HitTestProcessor2D aHitTestProcessor2D(
rViewInformation2D,
rHitPosition,
fLogicHitTolerance,
bTextOnly);
// ask for HitStack
aHitTestProcessor2D.collectHitStack(true);
// feed it with the primitives
aHitTestProcessor2D.process(rSequence);
// deliver result
if (aHitTestProcessor2D.getHit())
{
if (pHitContainer)
{
// fetch HitStack primitives if requested
*pHitContainer = aHitTestProcessor2D.getHitStack();
}
return true;
}
}
}
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */