LibreOffice Module svx (master)  1
viewcontactofsdrobjcustomshape.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 
21 #include <svx/svdoashp.hxx>
22 #include <svx/sdooitm.hxx>
26 #include <svx/obj3d.hxx>
27 #include <vcl/canvastools.hxx>
28 
29 
30 namespace sdr::contact
31 {
33  : ViewContactOfTextObj(rCustomShape)
34  {
35  }
36 
38  {
39  }
40 
42  {
43  const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
44  tools::Rectangle aTextBound(aObjectBound);
45  GetCustomShapeObj().GetTextBounds(aTextBound);
47  const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
48 
49  // no need to correct if no extra text range
50  if(aTextRange != aObjectRange)
51  {
52  const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
53 
54  // only correct when rotation and/or shear is used
55  if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle )
56  {
57  // text range needs to be corrected by
58  // aObjectRange.getCenter() - aRotObjectRange.getCenter() since it's
59  // defined differently by using rotation around object center. Start
60  // with positive part
61  basegfx::B2DVector aTranslation(aObjectRange.getCenter());
62 
63  // get rotated and sheared object's range
64  basegfx::B2DRange aRotObjectRange(aObjectRange);
65  basegfx::B2DHomMatrix aRotMatrix;
66 
67  aRotMatrix.translate(-aObjectRange.getMinimum().getX(), -aObjectRange.getMinimum().getY());
68 
69  if(rGeoStat.nShearAngle)
70  {
71  aRotMatrix.shearX(-rGeoStat.mfTanShearAngle);
72  }
73 
74  if(rGeoStat.nRotationAngle)
75  {
76  aRotMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
77  }
78 
79  aRotMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
80  aRotObjectRange.transform(aRotMatrix);
81 
82  // add negative translation part
83  aTranslation -= aRotObjectRange.getCenter();
84 
85  // create new range
86  aTextRange = basegfx::B2DRange(
87  aTextRange.getMinX() + aTranslation.getX(), aTextRange.getMinY() + aTranslation.getY(),
88  aTextRange.getMaxX() + aTranslation.getX(), aTextRange.getMaxY() + aTranslation.getY());
89  }
90 
91  // NbcMirror() of SdrTextObj (from which SdrObjCustomShape is derived), adds a
92  // 180deg rotation around the shape center to GeoStat.nRotationAngle. So remove here the
93  // 180° rotation, which was added by GetTextBounds().
95  {
97  aObjectRange.getCenterX(), aObjectRange.getCenterY(), M_PI));
98  aTextRange.transform(aRotMatrix);
99  }
100  }
101 
102  return aTextRange;
103  }
104 
106  {
107  const SfxItemSet& rItemSet = GetCustomShapeObj().GetMergedItemSet();
108 
109  // #i98072# Get shadow and text; eventually suppress the text if it's
110  // a TextPath FontworkGallery object
113  rItemSet,
114  GetCustomShapeObj().getText(0),
115  GetCustomShapeObj().IsTextPath()));
117  bool bHasText(!aAttribute.getText().isDefault());
118 
119  // create Primitive2DContainer from sub-geometry
120  const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape();
121  bool b3DShape(false);
122 
123  if(pSdrObjRepresentation)
124  {
125  // tdf#118498 The processing of SdrObjListIter for SdrIterMode::DeepNoGroups
126  // did change for 3D-Objects, it now correctly enters and iterates the
127  // SdrObjects in the E3dScene (same as for SdrObjGroup). This is more correct
128  // as the old version which just checked for dynamic_cast<const SdrObjGroup*>
129  // and *only* entered these, ignoring E3dScene as grouping-object.
130  // But how to fix that? Taking back the SdrObjListIter change would be easy, but
131  // not correct. After checking ViewContactOfE3dScene and ViewContactOfGroup
132  // I see that both traverse their children by themselves (on VC-Level,
133  // see createViewIndependentPrimitive2DSequence implementations and usage of
134  // GetObjectCount()). Thus in principle iterating here (esp. 'deep') seems to
135  // be wrong anyways, it might have even created wrong and double geometries
136  // (only with complex CustomShapes with multiple representation SdrObjects and
137  // only visible when transparency involved, but runtime-expensive).
138  // Thus: Just do not iterate, will check behaviour deeply.
139  b3DShape = (nullptr != dynamic_cast< const E3dObject* >(pSdrObjRepresentation));
140  pSdrObjRepresentation->GetViewContact().getViewIndependentPrimitive2DContainer(xGroup);
141  }
142 
143  if(bHasText || !xGroup.empty())
144  {
145  // prepare text box geometry
146  basegfx::B2DHomMatrix aTextBoxMatrix;
147  bool bWordWrap(false);
148 
149  // take unrotated snap rect as default, then get the
150  // unrotated text box. Rotation needs to be done centered
151  const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
152  const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
153 
154  if(bHasText)
155  {
156  // #i101684# get the text range unrotated and absolute to the object range
157  const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect());
158 
159  // Rotation before scaling
160  if(!basegfx::fTools::equalZero(GetCustomShapeObj().GetExtraTextRotation(true)))
161  {
162  basegfx::B2DVector aTranslation(0.5, 0.5);
163  aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
164  aTextBoxMatrix.rotate(basegfx::deg2rad(
165  360.0 - GetCustomShapeObj().GetExtraTextRotation(true)));
166  aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
167  }
168  // give text object a size
169  aTextBoxMatrix.scale(aTextRange.getWidth(), aTextRange.getHeight());
170 
171  // check if we have a rotation/shear at all to take care of
172  const double fExtraTextRotation(GetCustomShapeObj().GetExtraTextRotation());
173  const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
174 
175  if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle || !basegfx::fTools::equalZero(fExtraTextRotation))
176  {
177  if(aObjectRange != aTextRange)
178  {
179  // move relative to unrotated object range
180  aTextBoxMatrix.translate(
181  aTextRange.getMinX() - aObjectRange.getMinimum().getX(),
182  aTextRange.getMinY() - aObjectRange.getMinimum().getY());
183  }
184 
185  if(!basegfx::fTools::equalZero(fExtraTextRotation))
186  {
187  basegfx::B2DVector aTranslation(
188  ( aTextRange.getWidth() / 2 ) + ( aTextRange.getMinX() - aObjectRange.getMinimum().getX() ),
189  ( aTextRange.getHeight() / 2 ) + ( aTextRange.getMinY() - aObjectRange.getMinimum().getY() ) );
190  aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
191  aTextBoxMatrix.rotate(basegfx::deg2rad(360.0 - fExtraTextRotation));
192  aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
193  }
194 
195  if(rGeoStat.nShearAngle)
196  {
197  aTextBoxMatrix.shearX(-rGeoStat.mfTanShearAngle);
198  }
199 
200  if(rGeoStat.nRotationAngle)
201  {
202  aTextBoxMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
203  }
204 
205  // give text it's target position
206  aTextBoxMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
207  }
208  else
209  {
210  aTextBoxMatrix.translate(aTextRange.getMinX(), aTextRange.getMinY());
211  }
212 
213  // check if SdrTextWordWrapItem is set
214  bWordWrap = GetCustomShapeObj().GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue();
215  }
216 
217  // fill object matrix
219  aObjectRange.getWidth(), aObjectRange.getHeight(),
220  /*fShearX=*/0, /*fRotate=*/0,
221  aObjectRange.getMinX(), aObjectRange.getMinY()));
222 
223  // create primitive
226  aAttribute,
227  std::move(xGroup),
228  aTextBoxMatrix,
229  bWordWrap,
230  b3DShape,
231  aObjectMatrix));
232  rVisitor.visit(xReference);
233  }
234  }
235 
236 } // end of namespace
237 
238 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double getY() const
B2DPoint getCenter() const
bool equalZero(const T &rfVal)
constexpr double deg2rad(double v)
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
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
constexpr TypedWhichId< SdrOnOffItem > SDRATTR_TEXT_WORDWRAP(SDRATTR_MISC_FIRST+24)
double mfTanShearAngle
Definition: svdtrans.hxx:205
void shearX(double fSx)
virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor) const override
virtual void visit(const Primitive2DReference &)=0
void rotate(double fRadiant)
void scale(double fX, double fY)
double toRadians(D x)
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2007
Abstract DrawObject.
Definition: svdobj.hxx:259
attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(const SfxItemSet &rSet, const SdrText *pText, bool bSuppressText)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
const SdrObject * GetSdrObjectFromCustomShape() const
Definition: svdoashp.cxx:408
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
Degree100 nRotationAngle
Definition: svdtrans.hxx:203
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1972
B2DPoint getMinimum() const
bool GetTextBounds(tools::Rectangle &rTextBound) const
Definition: svdoashp.cxx:519
void translate(double fX, double fY)
double getX() const
bool IsMirroredY() const
Definition: svdoashp.cxx:480
Degree100 nShearAngle
Definition: svdtrans.hxx:204