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 <osl/diagnose.h>
32 #include <unotools/configmgr.hxx>
33 #include <vcl/canvastools.hxx>
34 
35 namespace sdr::contact
36 {
38  : ViewContactOfTextObj(rPathObj)
39  {
40  }
41 
43  {
44  }
45 
47  static bool ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
48  {
49  sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
50  sal_uInt32 nPointCount(0);
51 
52  for(auto const& rPolygon : std::as_const(rUnitPolyPolygon))
53  {
54  nPointCount += rPolygon.count();
55  if (nPointCount > 1)
56  return false;
57  }
58 
59  if(!nPointCount)
60  {
61  OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
62  basegfx::B2DPolygon aFallbackLine;
63  aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
64  aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
65  rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);
66 
67  nPolyCount = 1;
68  }
69 
70  return nPolyCount == 1;
71  }
72 
74  {
75  const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
78  rItemSet,
79  GetPathObj().getText(0),
80  false));
81  basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
82  bool bPolyCountIsOne(ensureGeometry(aUnitPolyPolygon));
83 
84  // prepare object transformation and unit polygon (direct model data)
85  basegfx::B2DHomMatrix aObjectMatrix;
86  basegfx::B2DPolyPolygon aUnitDefinitionPolyPolygon;
87  bool bIsLine(
88  !aUnitPolyPolygon.areControlPointsUsed()
89  && bPolyCountIsOne
90  && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
91 
92  if(bIsLine)
93  {
94  //tdf#63955 if we have an extremely long line then clip it to a
95  //very generous range of -1 page width/height vs +1 page
96  //width/height to avoid oom and massive churn generating a huge
97  //polygon chain to cover the length in applyLineDashing if this
98  //line is dashed
99  const SdrPage* pPage(GetPathObj().getSdrPageFromSdrObject());
100  sal_Int32 nPageWidth = pPage ? pPage->GetWidth() : 0;
101  sal_Int32 nPageHeight = pPage ? pPage->GetHeight() : 0;
102 
103  //But, see tdf#101187, only do this if our generous clip region
104  //would not over flow into a tiny clip region
105  if (nPageWidth < SAL_MAX_INT32/2 && nPageHeight < SAL_MAX_INT32/2 && !utl::ConfigManager::IsFuzzing())
106  {
107  //But, see tdf#97276, tdf#126184 and tdf#98366. Don't clip too much if the
108  //underlying page dimension is unknown or a paste document
109  //where the page sizes use the odd default of 10x10
110  const sal_Int32 nMaxPaperWidth = SvtOptionsDrawinglayer::GetMaximumPaperWidth() * 1000;
111  const sal_Int32 nMaxPaperHeight = SvtOptionsDrawinglayer::GetMaximumPaperHeight() * 1000;
112  nPageWidth = std::max<sal_Int32>(nPageWidth, nMaxPaperWidth);
113  nPageHeight = std::max<sal_Int32>(nPageHeight, nMaxPaperHeight);
114  basegfx::B2DRange aClipRange(-nPageWidth, -nPageHeight,
115  nPageWidth*2, nPageHeight*2);
116 
117  aUnitPolyPolygon = basegfx::utils::clipPolyPolygonOnRange(aUnitPolyPolygon,
118  aClipRange, true, true);
119  bPolyCountIsOne = ensureGeometry(aUnitPolyPolygon);
120 
121  // re-check that we have't been clipped out to oblivion
122  bIsLine =
123  !aUnitPolyPolygon.areControlPointsUsed()
124  && bPolyCountIsOne
125  && 2 == aUnitPolyPolygon.getB2DPolygon(0).count();
126  }
127  }
128 
129  if(bIsLine)
130  {
131 
132  // special handling for single line mode (2 points)
133  const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
134  const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
135  const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
136  const basegfx::B2DVector aLine(aEnd - aStart);
137 
138  // #i102548# create new unit polygon for line (horizontal)
139  basegfx::B2DPolygon aNewPolygon;
140  aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
141  aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
142  aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);
143 
144  // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
146  aLine.getLength(), 1.0,
147  0.0,
148  atan2(aLine.getY(), aLine.getX()),
149  aStart.getX(), aStart.getY());
150  }
151  else
152  {
153  // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
154  // (unit polygon) by creating the object matrix and back-transforming the polygon
155  const basegfx::B2DRange aObjectRange(basegfx::utils::getRange(aUnitPolyPolygon));
156  const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
157  const double fWidth(aObjectRange.getWidth());
158  const double fHeight(aObjectRange.getHeight());
159  const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
160  const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);
161 
163  fScaleX, fScaleY,
164  -rGeoStat.mfTanShearAngle,
165  rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
166  aObjectRange.getMinX(), aObjectRange.getMinY());
167 
168  // create unit polygon from object's absolute path
169  basegfx::B2DHomMatrix aInverse(aObjectMatrix);
170  aInverse.invert();
171  aUnitPolyPolygon.transform(aInverse);
172 
173  // OperationSmiley: Check if a FillGeometryDefiningShape is set
174  const SdrObject* pFillGeometryDefiningShape(GetPathObj().getFillGeometryDefiningShape());
175 
176  if(nullptr != pFillGeometryDefiningShape)
177  {
178  // If yes, get it's BoundRange and use as defining Geometry for the FillStyle.
179  // If no, aUnitDefinitionPolyPolygon will just be empty and thus be interpreted
180  // as unused.
181  // Using SnapRect will make the FillDefinition to always be extended e.g.
182  // for rotated/sheared objects.
183  const tools::Rectangle& rSnapRect(pFillGeometryDefiningShape->GetSnapRect());
184 
185  aUnitDefinitionPolyPolygon.append(
188 
189  // use same coordinate system as the shape geometry -> this
190  // makes it relative to shape's unit geometry and thus freely
191  // transformable with the shape
192  aUnitDefinitionPolyPolygon.transform(aInverse);
193  }
194  }
195 
196  // create primitive. Always create primitives to allow the decomposition of
197  // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
200  aObjectMatrix,
201  aAttribute,
202  aUnitPolyPolygon,
203  aUnitDefinitionPolyPolygon));
204 
205  rVisitor.visit(xReference);
206  }
207 
208 } // end of namespace
209 
210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
tools::Long GetWidth() const
Definition: svdpage.cxx:1448
bool equalZero(const T &rfVal)
void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon &rPolygon)
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1660
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) 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:201
static bool IsFuzzing()
double mfTanShearAngle
Definition: svdtrans.hxx:205
static bool ensureGeometry(basegfx::B2DPolyPolygon &rUnitPolyPolygon)
return true if polycount == 1
#define SAL_MAX_INT32
virtual void visit(const Primitive2DReference &)=0
tools::Long GetHeight() const
Definition: svdpage.cxx:1474
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor) const override
double toRadians(D x)
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)
sal_uInt32 count() const
Degree100 nRotationAngle
Definition: svdtrans.hxx:203
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1972
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:373
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