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
30namespace 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.m_nShearAngle || rGeoStat.m_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.m_nShearAngle)
70 {
71 aRotMatrix.shearX(-rGeoStat.mfTanShearAngle);
72 }
73
74 if(rGeoStat.m_nRotationAngle)
75 {
76 aRotMatrix.rotate(toRadians(36000_deg100 - rGeoStat.m_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().
94 if(GetCustomShapeObj().IsMirroredY())
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 != DynCastE3dObject(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
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.m_nShearAngle || rGeoStat.m_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.m_nShearAngle)
196 {
197 aTextBoxMatrix.shearX(-rGeoStat.mfTanShearAngle);
198 }
199
200 if(rGeoStat.m_nRotationAngle)
201 {
202 aTextBoxMatrix.rotate(toRadians(36000_deg100 - rGeoStat.m_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: */
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:201
double mfTanShearAngle
Definition: svdtrans.hxx:205
Degree100 m_nShearAngle
Definition: svdtrans.hxx:204
Degree100 m_nRotationAngle
Definition: svdtrans.hxx:203
const SdrObject * GetSdrObjectFromCustomShape() const
Definition: svdoashp.cxx:407
bool GetTextBounds(tools::Rectangle &rTextBound) const
Definition: svdoashp.cxx:538
Abstract DrawObject.
Definition: svdobj.hxx:260
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2009
sdr::contact::ViewContact & GetViewContact() const
Definition: svdobj.cxx:261
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1974
void shearX(double fSx)
void rotate(double fRadiant)
void translate(double fX, double fY)
void scale(double fX, double fY)
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
B2DPoint getCenter() const
B2DPoint getMinimum() const
TYPE getMaxX() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
double getCenterX() const
double getCenterY() const
TYPE getMaxY() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
virtual void visit(const Primitive2DReference &)=0
virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor) const override
void getViewIndependentPrimitive2DContainer(drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor) const
double toRadians(D x)
bool equalZero(const T &rfVal)
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
constexpr double deg2rad(double v)
attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(const SfxItemSet &rSet, const SdrText *pText, bool bSuppressText)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
constexpr TypedWhichId< SdrOnOffItem > SDRATTR_TEXT_WORDWRAP(SDRATTR_MISC_FIRST+24)
E3dObject * DynCastE3dObject(SdrObject *pObj)
Definition: svdobj.cxx:3205