LibreOffice Module svx (master)  1
viewcontactofsdrpathobj.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
23 #include <svx/svdopath.hxx>
24 #include <svx/svdpage.hxx>
31 #include <unotools/configmgr.hxx>
32 #include <vcl/canvastools.hxx>
33 
34 namespace sdr::contact
35 {
37  : ViewContactOfTextObj(rPathObj)
38  {
39  }
40 
42  {
43  }
44 
45  static sal_uInt32 ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
46  {
47  sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
48  sal_uInt32 nPointCount(0);
49 
50  for(auto const& rPolygon : std::as_const(rUnitPolyPolygon))
51  {
52  nPointCount += rPolygon.count();
53  }
54 
55  if(!nPointCount)
56  {
57  OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
58  basegfx::B2DPolygon aFallbackLine;
59  aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
60  aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
61  rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);
62 
63  nPolyCount = 1;
64  }
65 
66  return nPolyCount;
67  }
68 
70  {
71  const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
74  rItemSet,
75  GetPathObj().getText(0),
76  false));
77  basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
78  sal_uInt32 nPolyCount(ensureGeometry(aUnitPolyPolygon));
79 
80  // prepare object transformation and unit polygon (direct model data)
81  basegfx::B2DHomMatrix aObjectMatrix;
82  basegfx::B2DPolyPolygon aUnitDefinitionPolyPolygon;
83  bool bIsLine(
84  !aUnitPolyPolygon.areControlPointsUsed()
85  && 1 == nPolyCount
86  && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
87 
88  if(bIsLine)
89  {
90  //tdf#63955 if we have an extremely long line then clip it to a
91  //very generous range of -1 page width/height vs +1 page
92  //width/height to avoid oom and massive churn generating a huge
93  //polygon chain to cover the length in applyLineDashing if this
94  //line is dashed
95  const SdrPage* pPage(GetPathObj().getSdrPageFromSdrObject());
96  sal_Int32 nPageWidth = pPage ? pPage->GetWidth() : 0;
97  sal_Int32 nPageHeight = pPage ? pPage->GetHeight() : 0;
98 
99  //But, see tdf#101187, only do this if our generous clip region
100  //would not over flow into a tiny clip region
101  if (nPageWidth < SAL_MAX_INT32/2 && nPageHeight < SAL_MAX_INT32/2 && !utl::ConfigManager::IsFuzzing())
102  {
103  //But, see tdf#97276, tdf#126184 and tdf#98366. Don't clip too much if the
104  //underlying page dimension is unknown or a paste document
105  //where the page sizes use the odd default of 10x10
106  const sal_Int32 nMaxPaperWidth = SvtOptionsDrawinglayer::GetMaximumPaperWidth() * 1000;
107  const sal_Int32 nMaxPaperHeight = SvtOptionsDrawinglayer::GetMaximumPaperHeight() * 1000;
108  nPageWidth = std::max<sal_Int32>(nPageWidth, nMaxPaperWidth);
109  nPageHeight = std::max<sal_Int32>(nPageHeight, nMaxPaperHeight);
110  basegfx::B2DRange aClipRange(-nPageWidth, -nPageHeight,
111  nPageWidth*2, nPageHeight*2);
112 
113  aUnitPolyPolygon = basegfx::utils::clipPolyPolygonOnRange(aUnitPolyPolygon,
114  aClipRange, true, true);
115  nPolyCount = ensureGeometry(aUnitPolyPolygon);
116 
117  // re-check that we have't been clipped out to oblivion
118  bIsLine =
119  !aUnitPolyPolygon.areControlPointsUsed()
120  && 1 == nPolyCount
121  && 2 == aUnitPolyPolygon.getB2DPolygon(0).count();
122  }
123  }
124 
125  if(bIsLine)
126  {
127 
128  // special handling for single line mode (2 points)
129  const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
130  const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
131  const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
132  const basegfx::B2DVector aLine(aEnd - aStart);
133 
134  // #i102548# create new unit polygon for line (horizontal)
135  basegfx::B2DPolygon aNewPolygon;
136  aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
137  aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
138  aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);
139 
140  // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
142  aLine.getLength(), 1.0,
143  0.0,
144  atan2(aLine.getY(), aLine.getX()),
145  aStart.getX(), aStart.getY());
146  }
147  else
148  {
149  // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
150  // (unit polygon) by creating the object matrix and back-transforming the polygon
151  const basegfx::B2DRange aObjectRange(basegfx::utils::getRange(aUnitPolyPolygon));
152  const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
153  const double fWidth(aObjectRange.getWidth());
154  const double fHeight(aObjectRange.getHeight());
155  const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
156  const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);
157 
159  fScaleX, fScaleY,
160  -rGeoStat.mfTanShearAngle,
161  rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle.get()) * F_PI18000 : 0.0,
162  aObjectRange.getMinX(), aObjectRange.getMinY());
163 
164  // create unit polygon from object's absolute path
165  basegfx::B2DHomMatrix aInverse(aObjectMatrix);
166  aInverse.invert();
167  aUnitPolyPolygon.transform(aInverse);
168 
169  // OperationSmiley: Check if a FillGeometryDefiningShape is set
170  const SdrObject* pFillGeometryDefiningShape(GetPathObj().getFillGeometryDefiningShape());
171 
172  if(nullptr != pFillGeometryDefiningShape)
173  {
174  // If yes, get it's BoundRange and use as defining Geometry for the FillStyle.
175  // If no, aUnitDefinitionPolyPolygon will just be empty and thus be interpreted
176  // as unused.
177  // Using SnapRect will make the FillDefinition to always be extended e.g.
178  // for rotated/sheared objects.
179  const tools::Rectangle& rSnapRect(pFillGeometryDefiningShape->GetSnapRect());
180 
181  aUnitDefinitionPolyPolygon.append(
184 
185  // use same coordinate system as the shape geometry -> this
186  // makes it relative to shape's unit geometry and thus freely
187  // transformable with the shape
188  aUnitDefinitionPolyPolygon.transform(aInverse);
189  }
190  }
191 
192  // create primitive. Always create primitives to allow the decomposition of
193  // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
196  aObjectMatrix,
197  aAttribute,
198  aUnitPolyPolygon,
199  aUnitDefinitionPolyPolygon));
200 
202  }
203 
204 } // end of namespace
205 
206 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static sal_uInt32 ensureGeometry(basegfx::B2DPolyPolygon &rUnitPolyPolygon)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
double getHeight() const
sal_Int32 GetHeight() const
Definition: svdpage.cxx:1454
bool equalZero(const T &rfVal)
void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon &rPolygon)
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1666
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
double getWidth() const
B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:214
static bool IsFuzzing()
double mfTanShearAngle
Definition: svdtrans.hxx:218
virtual drawinglayer::primitive2d::Primitive2DContainer createViewIndependentPrimitive2DSequence() const override
UNDERLYING_TYPE get() const
#define SAL_MAX_INT32
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
Abstract DrawObject.
Definition: svdobj.hxx:259
B2DRange getRange(const B2DPolygon &rCandidate)
sal_uInt32 GetMaximumPaperHeight()
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
double getMinY() const
sal_uInt32 count() const
Degree100 nRotationAngle
Definition: svdtrans.hxx:216
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1978
#define F_PI18000
double getMinX() const
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:365
sal_Int32 GetWidth() const
Definition: svdpage.cxx:1428
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
bool areControlPointsUsed() const
sal_uInt32 GetMaximumPaperWidth()
attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(const SfxItemSet &rSet, const SdrText *pText, bool bHasContent)
sal_uInt32 count() const