summaryrefslogtreecommitdiff
path: root/svx
diff options
context:
space:
mode:
authorArmin Le Grand <Armin.Le.Grand@cib.de>2017-07-31 14:46:03 +0200
committerArmin Le Grand <Armin.Le.Grand@cib.de>2017-08-16 16:06:00 +0200
commite4de923e0e771e40414d6b3b9b77389b457aa562 (patch)
tree7e79f6b136ffbd7a81e364e3e0cc0919d38dd807 /svx
parentd40d63030d965df16d428660635d0bb945dd36b2 (diff)
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>
Diffstat (limited to 'svx')
-rw-r--r--svx/source/svdraw/sdrhittesthelper.cxx22
-rw-r--r--svx/source/svdraw/svdotextdecomposition.cxx13
-rw-r--r--svx/source/svdraw/svdview.cxx92
3 files changed, 85 insertions, 42 deletions
diff --git a/svx/source/svdraw/sdrhittesthelper.cxx b/svx/source/svdraw/sdrhittesthelper.cxx
index ec3a4d21dba0..ff8dfbca6f0c 100644
--- a/svx/source/svdraw/sdrhittesthelper.cxx
+++ b/svx/source/svdraw/sdrhittesthelper.cxx
@@ -39,7 +39,8 @@ SdrObject* SdrObjectPrimitiveHit(
sal_uInt16 nTol,
const SdrPageView& rSdrPageView,
const SetOfByte* pVisiLayer,
- bool bTextOnly)
+ bool bTextOnly,
+ drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
{
SdrObject* pResult = nullptr;
@@ -77,7 +78,7 @@ SdrObject* SdrObjectPrimitiveHit(
const sdr::contact::ViewObjectContact& rVOC = rObject.GetViewContact().GetViewObjectContact(
rSdrPageView.GetPageWindow(0)->GetObjectContact());
- if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly))
+ if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly, pHitContainer))
{
pResult = const_cast< SdrObject* >(&rObject);
}
@@ -117,7 +118,8 @@ bool ViewObjectContactPrimitiveHit(
const sdr::contact::ViewObjectContact& rVOC,
const basegfx::B2DPoint& rHitPosition,
double fLogicHitTolerance,
- bool bTextOnly)
+ bool bTextOnly,
+ drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
{
basegfx::B2DRange aObjectRange(rVOC.getObjectRange());
@@ -146,11 +148,23 @@ bool ViewObjectContactPrimitiveHit(
fLogicHitTolerance,
bTextOnly);
+ // ask for HitStack
+ aHitTestProcessor2D.collectHitStack(true);
+
// feed it with the primitives
aHitTestProcessor2D.process(rSequence);
// deliver result
- return aHitTestProcessor2D.getHit();
+ if (aHitTestProcessor2D.getHit())
+ {
+ if (pHitContainer)
+ {
+ // fetch HitStack primitives if requested
+ *pHitContainer = aHitTestProcessor2D.getHitStack();
+ }
+
+ return true;
+ }
}
}
}
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 9b6a8c9eaa3a..3de59d7deed0 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -479,15 +479,22 @@ namespace
if(pURLField)
{
- pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, pURLField->GetURL());
+ // extended this to hold more of the contents of the original
+ // SvxURLField since that stuff is still used in HitTest and e.g. Calc
+ std::vector< std::pair< OUString, OUString>> meValues;
+ meValues.push_back(std::pair< OUString, OUString>("URL", pURLField->GetURL()));
+ meValues.push_back(std::pair< OUString, OUString>("Representation", pURLField->GetRepresentation()));
+ meValues.push_back(std::pair< OUString, OUString>("TargetFrame", pURLField->GetTargetFrame()));
+ meValues.push_back(std::pair< OUString, OUString>("SvxURLFormat", OUString::number(static_cast<sal_uInt16>(pURLField->GetFormat()))));
+ pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, &meValues);
}
else if(pPageField)
{
- pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE, "");
+ pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE);
}
else
{
- pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON, "");
+ pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON);
}
}
diff --git a/svx/source/svdraw/svdview.cxx b/svx/source/svdraw/svdview.cxx
index bc0475cc07a9..0640149ea831 100644
--- a/svx/source/svdraw/svdview.cxx
+++ b/svx/source/svdraw/svdview.cxx
@@ -49,6 +49,7 @@
#include <svx/sdrhittesthelper.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <drawinglayer/processor2d/contourextractor2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
SdrViewEvent::SdrViewEvent()
@@ -448,45 +449,66 @@ SdrHitKind SdrView::PickAnything(const Point& rLogicPos, SdrViewEvent& rVEvt) co
SdrTextObj* pTextObj=dynamic_cast<SdrTextObj*>( pHitObj );
if (pTextObj!=nullptr && pTextObj->HasText())
{
- bool bTEHit(pPV &&
- SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true));
-
- if (bTEHit)
+ // use the primitive-based HitTest which is more accurate anyways. It
+ // will correctly handle rotated/mirrored/sheared/scaled text and can
+ // now return a HitContainer containing the primitive hierarchy of the
+ // primitive that triggered the hit. The first entry is that primitive,
+ // the others are the full stack of primitives leading to that one which
+ // includes grouping primitives (like TextHierarchyPrimitives we deed here)
+ // but also all decomposed ones which lead to the creation of that primitive
+ drawinglayer::primitive2d::Primitive2DContainer aHitContainer;
+ const bool bTEHit(pPV && SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true, &aHitContainer));
+
+ if (bTEHit && !aHitContainer.empty())
{
- Rectangle aTextRect;
- Rectangle aAnchor;
- SdrOutliner* pOutliner = &pTextObj->ImpGetDrawOutliner();
- if( pTextObj->GetModel() )
- pOutliner = &pTextObj->GetModel()->GetHitTestOutliner();
-
- pTextObj->TakeTextRect( *pOutliner, aTextRect, false, &aAnchor, false );
-
- // #i73628# Use a text-relative position for hit test in hit test outliner
- Point aTemporaryTextRelativePosition(aLocalLogicPosition - aTextRect.TopLeft());
-
- // account for FitToSize
- bool bFitToSize(pTextObj->IsFitToSize());
- if (bFitToSize) {
- Fraction aX(aTextRect.GetWidth()-1,aAnchor.GetWidth()-1);
- Fraction aY(aTextRect.GetHeight()-1,aAnchor.GetHeight()-1);
- ResizePoint(aTemporaryTextRelativePosition,Point(),aX,aY);
+ // search for TextHierarchyFieldPrimitive2D which contains the needed information
+ // about a possible URLField
+ const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D* pTextHierarchyFieldPrimitive2D = nullptr;
+
+ for (const drawinglayer::primitive2d::Primitive2DReference& xReference : aHitContainer)
+ {
+ if (xReference.is())
+ {
+ // try to cast to drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D implementation
+ pTextHierarchyFieldPrimitive2D = dynamic_cast<const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D*>(xReference.get());
+
+ if (pTextHierarchyFieldPrimitive2D)
+ {
+ break;
+ }
+ }
}
- // account for rotation
- const GeoStat& rGeo=pTextObj->GetGeoStat();
- if (rGeo.nRotationAngle!=0) RotatePoint(aTemporaryTextRelativePosition,Point(),-rGeo.nSin,rGeo.nCos); // -sin for Unrotate
- // we currently don't account for ticker text
- if(mpActualOutDev && mpActualOutDev->GetOutDevType() == OUTDEV_WINDOW)
+
+ if (nullptr != pTextHierarchyFieldPrimitive2D)
{
- OutlinerView aOLV(pOutliner, const_cast<vcl::Window*>(static_cast<const vcl::Window*>(mpActualOutDev.get())));
- const EditView& aEV=aOLV.GetEditView();
- const SvxFieldItem* pItem=aEV.GetField(aTemporaryTextRelativePosition);
- if (pItem!=nullptr) {
- const SvxFieldData* pFld=pItem->GetField();
- const SvxURLField* pURL=dynamic_cast<const SvxURLField*>( pFld );
- if (pURL!=nullptr) {
- eHit=SDRHIT_URLFIELD;
- rVEvt.pURLField=pURL;
+ if (drawinglayer::primitive2d::FieldType::FIELD_TYPE_URL == pTextHierarchyFieldPrimitive2D->getType())
+ {
+ // problem with the old code is that a *pointer* to an instance of
+ // SvxURLField is set in the Event which is per se not good since that
+ // data comes from a temporary EditEngine's data and could vanish any
+ // moment. Have to replace for now with a static instance that gets
+ // filled/initialized from the original data held in the TextHierarchyField-
+ // Primitive2D (see impTextBreakupHandler::impCheckFieldPrimitive).
+ // Unfortunately things like 'TargetFrame' are still used in Calc, so this
+ // can currently not get replaced. For the future the Name/Value vector or
+ // the TextHierarchyFieldPrimitive2D itself should/will be used for handling
+ // that data
+ static SvxURLField aSvxURLField;
+
+ aSvxURLField.SetURL(pTextHierarchyFieldPrimitive2D->getValue("URL"));
+ aSvxURLField.SetRepresentation(pTextHierarchyFieldPrimitive2D->getValue("Representation"));
+ aSvxURLField.SetTargetFrame(pTextHierarchyFieldPrimitive2D->getValue("TargetFrame"));
+ const OUString aFormat(pTextHierarchyFieldPrimitive2D->getValue("SvxURLFormat"));
+
+ if (!aFormat.isEmpty())
+ {
+ aSvxURLField.SetFormat(static_cast<SvxURLFormat>(aFormat.toInt32()));
}
+
+ // set HitKind and pointer to local static instance in the Event
+ // to comply to old stuff
+ eHit = SDRHIT_URLFIELD;
+ rVEvt.pURLField = &aSvxURLField;
}
}
}