1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdtrans.hxx>
23 #include <svx/svdogrp.hxx>
24 #include <svx/svdopath.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdmodel.hxx>
27 #include <sdr/properties/itemsettools.hxx>
28 #include <svx/sdr/properties/properties.hxx>
29 #include <basegfx/polygon/b2dpolypolygontools.hxx>
30 #include <svl/itemset.hxx>
31 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
32 #include <svx/sdr/contact/viewcontact.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xflclit.hxx>
35 #include <svx/xlineit0.hxx>
36 #include <svx/xlnclit.hxx>
37 #include <svx/xlnwtit.hxx>
38 #include <svx/sdshitm.hxx>
39 #include <unotools/configmgr.hxx>
41 using namespace com::sun::star
;
43 void SdrTextObj::NbcSetSnapRect(const tools::Rectangle
& rRect
)
45 if (maGeo
.nRotationAngle
|| maGeo
.nShearAngle
)
47 // Either the rotation or shear angle exists.
48 tools::Rectangle
aSR0(GetSnapRect());
49 tools::Long nWdt0
=aSR0
.Right()-aSR0
.Left();
50 tools::Long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
51 tools::Long nWdt1
=rRect
.Right()-rRect
.Left();
52 tools::Long nHgt1
=rRect
.Bottom()-rRect
.Top();
53 SdrTextObj::NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
54 SdrTextObj::NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
58 // No rotation or shear.
61 ImpJustifyRect(maRectangle
);
66 SetBoundAndSnapRectsDirty();
70 const tools::Rectangle
& SdrTextObj::GetLogicRect() const
72 return getRectangle();
75 void SdrTextObj::NbcSetLogicRect(const tools::Rectangle
& rRect
)
78 ImpJustifyRect(maRectangle
);
82 SetBoundAndSnapRectsDirty();
85 Degree100
SdrTextObj::GetRotateAngle() const
87 return maGeo
.nRotationAngle
;
90 Degree100
SdrTextObj::GetShearAngle(bool /*bVertical*/) const
92 return maGeo
.nShearAngle
;
95 void SdrTextObj::NbcMove(const Size
& rSize
)
97 moveRectangle(rSize
.Width(), rSize
.Height());
98 moveOutRectangle(rSize
.Width(), rSize
.Height());
99 maSnapRect
.Move(rSize
);
100 SetBoundAndSnapRectsDirty(true);
103 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
105 bool bNotSheared
=maGeo
.nShearAngle
==0_deg100
;
106 bool bRotate90
=bNotSheared
&& maGeo
.nRotationAngle
.get() % 9000 ==0;
107 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
108 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
109 if (bXMirr
|| bYMirr
) {
110 Point
aRef1(GetSnapRect().Center());
114 NbcMirrorGluePoints(aRef1
,aRef2
);
119 NbcMirrorGluePoints(aRef1
,aRef2
);
123 if (maGeo
.nRotationAngle
==0_deg100
&& maGeo
.nShearAngle
==0_deg100
) {
124 auto aRectangle
= getRectangle();
125 ResizeRect(aRectangle
, rRef
, xFact
, yFact
);
126 setRectangle(aRectangle
);
129 maRectangle
.Normalize();
130 moveRectangle(aRectangle
.Right() - aRectangle
.Left(), aRectangle
.Bottom() - aRectangle
.Top());
131 maGeo
.nRotationAngle
=18000_deg100
;
132 maGeo
.RecalcSinCos();
137 tools::Polygon
aPol(Rect2Poly(getRectangle(), maGeo
));
139 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
141 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
146 // turn polygon and move it a little
147 tools::Polygon
aPol0(aPol
);
155 tools::Rectangle aRectangle
= svx::polygonToRectangle(aPol
, maGeo
);
156 setRectangle(aRectangle
);
160 bool bRota90
=maGeo
.nRotationAngle
.get() % 9000 ==0;
161 if (!bRota90
) { // there's seems to be a rounding error occurring: correct it
162 Degree100 a
=NormAngle36000(maGeo
.nRotationAngle
);
163 if (a
<4500_deg100
) a
=0_deg100
;
164 else if (a
<13500_deg100
) a
=9000_deg100
;
165 else if (a
<22500_deg100
) a
=18000_deg100
;
166 else if (a
<31500_deg100
) a
=27000_deg100
;
168 maGeo
.nRotationAngle
=a
;
169 maGeo
.RecalcSinCos();
171 if (bNotSheared
!=(maGeo
.nShearAngle
==0_deg100
)) { // correct a rounding error occurring with Shear
172 maGeo
.nShearAngle
=0_deg100
;
177 ImpJustifyRect(maRectangle
);
181 if(mbTextFrame
&& !getSdrModelFromSdrObject().IsPasteResize())
183 NbcAdjustTextFrameWidthAndHeight();
187 SetBoundAndSnapRectsDirty();
190 void SdrTextObj::NbcRotate(const Point
& rRef
, Degree100 nAngle
, double sn
, double cs
)
192 SetGlueReallyAbsolute(true);
193 tools::Long dx
= getRectangle().Right() - getRectangle().Left();
194 tools::Long dy
= getRectangle().Bottom() - getRectangle().Top();
195 Point
aPoint1(getRectangle().TopLeft());
196 RotatePoint(aPoint1
, rRef
, sn
, cs
);
197 Point
aPoint2(aPoint1
.X() + dx
, aPoint1
.Y() + dy
);
198 tools::Rectangle
aRectangle(aPoint1
, aPoint2
);
199 setRectangle(aRectangle
);
201 if (maGeo
.nRotationAngle
==0_deg100
) {
202 maGeo
.nRotationAngle
=NormAngle36000(nAngle
);
203 maGeo
.mfSinRotationAngle
=sn
;
204 maGeo
.mfCosRotationAngle
=cs
;
206 maGeo
.nRotationAngle
=NormAngle36000(maGeo
.nRotationAngle
+nAngle
);
207 maGeo
.RecalcSinCos();
209 SetBoundAndSnapRectsDirty();
210 NbcRotateGluePoints(rRef
,nAngle
,sn
,cs
);
211 SetGlueReallyAbsolute(false);
214 void SdrTextObj::NbcShear(const Point
& rRef
, Degree100
/*nAngle*/, double tn
, bool bVShear
)
216 SetGlueReallyAbsolute(true);
218 // when this is a SdrPathObj, aRect may be uninitialized
219 tools::Polygon
aPol(Rect2Poly(getRectangle().IsEmpty() ? GetSnapRect() : getRectangle(), maGeo
));
221 sal_uInt16 nPointCount
=aPol
.GetSize();
222 for (sal_uInt16 i
=0; i
<nPointCount
; i
++) {
223 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
225 tools::Rectangle aRectangle
= svx::polygonToRectangle(aPol
, maGeo
);
226 setRectangle(aRectangle
);
227 ImpJustifyRect(maRectangle
);
230 NbcAdjustTextFrameWidthAndHeight();
233 SetBoundAndSnapRectsDirty();
234 NbcShearGluePoints(rRef
,tn
,bVShear
);
235 SetGlueReallyAbsolute(false);
238 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
240 SetGlueReallyAbsolute(true);
241 bool bNotSheared
=maGeo
.nShearAngle
==0_deg100
;
242 bool bRotate90
= false;
244 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
245 std::abs(rRef1
.X()-rRef2
.X())==std::abs(rRef1
.Y()-rRef2
.Y()))) {
246 bRotate90
=maGeo
.nRotationAngle
.get() % 9000 ==0;
248 tools::Polygon
aPol(Rect2Poly(getRectangle(),maGeo
));
250 sal_uInt16 nPointCount
=aPol
.GetSize();
251 for (i
=0; i
<nPointCount
; i
++) {
252 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
254 // turn polygon and move it a little
255 tools::Polygon
aPol0(aPol
);
261 tools::Rectangle aRectangle
= svx::polygonToRectangle(aPol
, maGeo
);
262 setRectangle(aRectangle
);
265 bool bRota90
=maGeo
.nRotationAngle
.get() % 9000 ==0;
266 if (bRotate90
&& !bRota90
) { // there's seems to be a rounding error occurring: correct it
267 Degree100 a
=NormAngle36000(maGeo
.nRotationAngle
);
268 if (a
<4500_deg100
) a
=0_deg100
;
269 else if (a
<13500_deg100
) a
=9000_deg100
;
270 else if (a
<22500_deg100
) a
=18000_deg100
;
271 else if (a
<31500_deg100
) a
=27000_deg100
;
273 maGeo
.nRotationAngle
=a
;
274 maGeo
.RecalcSinCos();
277 if (bNotSheared
!=(maGeo
.nShearAngle
==0_deg100
)) { // correct a rounding error occurring with Shear
278 maGeo
.nShearAngle
=0_deg100
;
282 ImpJustifyRect(maRectangle
);
284 NbcAdjustTextFrameWidthAndHeight();
287 SetBoundAndSnapRectsDirty();
288 NbcMirrorGluePoints(rRef1
,rRef2
);
289 SetGlueReallyAbsolute(false);
293 rtl::Reference
<SdrObject
> SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
295 rtl::Reference
<SdrObject
> pRetval
;
297 if(!ImpCanConvTextToCurve())
299 // suppress HelpTexts from PresObj's
303 // create an extractor with neutral ViewInformation
304 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
305 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
307 // extract text as polygons
308 GetViewContact().getViewIndependentPrimitive2DContainer(aExtractor
);
311 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
312 const sal_uInt32
nResultCount(rResult
.size());
316 // prepare own target
317 rtl::Reference
<SdrObjGroup
> pGroup
= new SdrObjGroup(getSdrModelFromSdrObject());
318 SdrObjList
* pObjectList
= pGroup
->GetSubList();
321 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
323 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
324 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
326 if(aPolyPolygon
.count())
328 // take care of wanted polygon type
331 if(aPolyPolygon
.areControlPointsUsed())
333 aPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon
);
338 if(!aPolyPolygon
.areControlPointsUsed())
340 aPolyPolygon
= basegfx::utils::expandToCurve(aPolyPolygon
);
344 // create ItemSet with object attributes
345 SfxItemSet
aAttributeSet(GetObjectItemSet());
346 rtl::Reference
<SdrPathObj
> pPathObj
;
348 // always clear objectshadow; this is included in the extraction
349 aAttributeSet
.Put(makeSdrShadowItem(false));
351 if(rCandidate
.getIsFilled())
354 aAttributeSet
.Put(XFillColorItem(OUString(), Color(rCandidate
.getBColor())));
355 aAttributeSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
356 aAttributeSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
358 // create filled SdrPathObj
359 pPathObj
= new SdrPathObj(
360 getSdrModelFromSdrObject(),
361 SdrObjKind::PathFill
,
367 aAttributeSet
.Put(XLineColorItem(OUString(), Color(rCandidate
.getBColor())));
368 aAttributeSet
.Put(XLineStyleItem(drawing::LineStyle_SOLID
));
369 aAttributeSet
.Put(XLineWidthItem(0));
370 aAttributeSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
372 // create line SdrPathObj
373 pPathObj
= new SdrPathObj(
374 getSdrModelFromSdrObject(),
375 SdrObjKind::PathLine
,
376 std::move(aPolyPolygon
));
379 // copy basic information from original
380 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
381 pPathObj
->NbcSetLayer(GetLayer());
382 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
384 // apply prepared ItemSet and add to target
385 pPathObj
->SetMergedItemSet(aAttributeSet
);
386 pObjectList
->InsertObject(pPathObj
.get());
390 // postprocess; if no result and/or only one object, simplify
391 if(!pObjectList
->GetObjCount())
395 else if(1 == pObjectList
->GetObjCount())
397 pRetval
= pObjectList
->RemoveObject(0);
410 rtl::Reference
<SdrObject
> SdrTextObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
414 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
420 bool SdrTextObj::ImpCanConvTextToCurve() const
422 return !IsOutlText() && !utl::ConfigManager::IsFuzzing();
425 rtl::Reference
<SdrPathObj
> SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, bool bClosed
, bool bBezier
) const
427 SdrObjKind ePathKind
= bClosed
? SdrObjKind::PathFill
: SdrObjKind::PathLine
;
428 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
433 aB2DPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
434 ePathKind
= bClosed
? SdrObjKind::Polygon
: SdrObjKind::PolyLine
;
437 rtl::Reference
<SdrPathObj
> pPathObj(new SdrPathObj(
438 getSdrModelFromSdrObject(),
440 std::move(aB2DPolyPolygon
)));
444 // create bezier curves
445 pPathObj
->SetPathPoly(basegfx::utils::expandToCurve(pPathObj
->GetPathPoly()));
448 pPathObj
->ImpSetAnchorPos(m_aAnchor
);
449 pPathObj
->NbcSetLayer(GetLayer());
450 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
451 pPathObj
->ClearMergedItem();
452 pPathObj
->SetMergedItemSet(GetObjectItemSet());
453 pPathObj
->GetProperties().BroadcastItemChange(aC
);
454 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
459 rtl::Reference
<SdrObject
> SdrTextObj::ImpConvertAddText(rtl::Reference
<SdrObject
> pObj
, bool bBezier
) const
461 if(!ImpCanConvTextToCurve())
466 rtl::Reference
<SdrObject
> pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
478 if(pText
->IsGroupObject())
480 // is already group object, add partial shape in front
481 SdrObjList
* pOL
=pText
->GetSubList();
482 pOL
->InsertObject(pObj
.get(),0);
488 // not yet a group, create one and add partial and new shapes
489 rtl::Reference
<SdrObjGroup
> pGrp(new SdrObjGroup(getSdrModelFromSdrObject()));
490 SdrObjList
* pOL
=pGrp
->GetSubList();
491 pOL
->InsertObject(pObj
.get());
492 pOL
->InsertObject(pText
.get());
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */