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 <vcl/canvastools.hxx>
32 
33 namespace sdr::contact
34 {
36  : ViewContactOfTextObj(rPathObj)
37  {
38  }
39 
41  {
42  }
43 
44  static sal_uInt32 ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
45  {
46  sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
47  sal_uInt32 nPointCount(0);
48 
49  for(auto const& rPolygon : rUnitPolyPolygon)
50  {
51  nPointCount += rPolygon.count();
52  }
53 
54  if(!nPointCount)
55  {
56  OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
57  basegfx::B2DPolygon aFallbackLine;
58  aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
59  aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
60  rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);
61 
62  nPolyCount = 1;
63  }
64 
65  return nPolyCount;
66  }
67 
69  {
70  const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
73  rItemSet,
74  GetPathObj().getText(0),
75  false));
76  basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
77  sal_uInt32 nPolyCount(ensureGeometry(aUnitPolyPolygon));
78 
79  // prepare object transformation and unit polygon (direct model data)
80  basegfx::B2DHomMatrix aObjectMatrix;
81  basegfx::B2DPolyPolygon aUnitDefinitionPolyPolygon;
82  bool bIsLine(
83  !aUnitPolyPolygon.areControlPointsUsed()
84  && 1 == nPolyCount
85  && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
86 
87  if(bIsLine)
88  {
89  //tdf#63955 if we have an extremely long line then clip it to a
90  //very generous range of -1 page width/height vs +1 page
91  //width/height to avoid oom and massive churn generating a huge
92  //polygon chain to cover the length in applyLineDashing if this
93  //line is dashed
94  const SdrPage* pPage(GetPathObj().getSdrPageFromSdrObject());
95  sal_Int32 nPageWidth = pPage ? pPage->GetWidth() : 0;
96  sal_Int32 nPageHeight = pPage ? pPage->GetHeight() : 0;
97 
98  //But, see tdf#101187, only do this if our generous clip region
99  //would not over flow into a tiny clip region
100  if (nPageWidth < SAL_MAX_INT32/2 && nPageHeight < SAL_MAX_INT32/2)
101  {
102  //But, see tdf#97276, tdf#126184 and tdf#98366. Don't clip too much if the
103  //underlying page dimension is unknown or a paste document
104  //where the page sizes use the odd default of 10x10
105  const SvtOptionsDrawinglayer aDrawinglayerOpt;
106  const sal_Int32 nMaxPaperWidth = aDrawinglayerOpt.GetMaximumPaperWidth() * 1000;
107  const sal_Int32 nMaxPaperHeight = aDrawinglayerOpt.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.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0,
161  rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * 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:1393
tools::Long nRotationAngle
Definition: svdtrans.hxx:216
void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon &rPolygon)
sal_uInt32 GetMaximumPaperWidth() const
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1598
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
virtual drawinglayer::primitive2d::Primitive2DContainer createViewIndependentPrimitive2DSequence() const override
#define SAL_MAX_INT32
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
static bool equalZero(const double &rfVal)
void transform(const basegfx::B2DHomMatrix &rMatrix)
Abstract DrawObject.
Definition: svdobj.hxx:260
B2DRange getRange(const B2DPolygon &rCandidate)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
sal_uInt32 GetMaximumPaperHeight() const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
double getMinY() const
sal_uInt32 count() const
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1890
#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
tools::Long nShearAngle
Definition: svdtrans.hxx:217
sal_Int32 GetWidth() const
Definition: svdpage.cxx:1367
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
bool areControlPointsUsed() const
attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(const SfxItemSet &rSet, const SdrText *pText, bool bHasContent)
sal_uInt32 count() const