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>
40 using namespace com::sun::star
;
42 void SdrTextObj::NbcSetSnapRect(const tools::Rectangle
& rRect
)
44 if (aGeo
.nRotationAngle
!=0 || aGeo
.nShearAngle
!=0)
46 // Either the rotation or shear angle exists.
47 tools::Rectangle
aSR0(GetSnapRect());
48 tools::Long nWdt0
=aSR0
.Right()-aSR0
.Left();
49 tools::Long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
50 tools::Long nWdt1
=rRect
.Right()-rRect
.Left();
51 tools::Long nHgt1
=rRect
.Bottom()-rRect
.Top();
52 SdrTextObj::NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
53 SdrTextObj::NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
57 // No rotation or shear.
60 ImpJustifyRect(maRect
);
69 const tools::Rectangle
& SdrTextObj::GetLogicRect() const
74 void SdrTextObj::NbcSetLogicRect(const tools::Rectangle
& rRect
)
77 ImpJustifyRect(maRect
);
84 tools::Long
SdrTextObj::GetRotateAngle() const
86 return aGeo
.nRotationAngle
;
89 tools::Long
SdrTextObj::GetShearAngle(bool /*bVertical*/) const
91 return aGeo
.nShearAngle
;
94 void SdrTextObj::NbcMove(const Size
& rSiz
)
98 maSnapRect
.Move(rSiz
);
102 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
104 bool bNotSheared
=aGeo
.nShearAngle
==0;
105 bool bRotate90
=bNotSheared
&& aGeo
.nRotationAngle
% 9000 ==0;
106 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
107 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
108 if (bXMirr
|| bYMirr
) {
109 Point
aRef1(GetSnapRect().Center());
113 NbcMirrorGluePoints(aRef1
,aRef2
);
118 NbcMirrorGluePoints(aRef1
,aRef2
);
122 if (aGeo
.nRotationAngle
==0 && aGeo
.nShearAngle
==0) {
123 ResizeRect(maRect
,rRef
,xFact
,yFact
);
126 maRect
.Move(maRect
.Right()-maRect
.Left(),maRect
.Bottom()-maRect
.Top());
127 aGeo
.nRotationAngle
=18000;
133 tools::Polygon
aPol(Rect2Poly(maRect
,aGeo
));
135 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
137 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
142 // turn polygon and move it a little
143 tools::Polygon
aPol0(aPol
);
152 Poly2Rect(aPol
, maRect
, aGeo
);
156 bool bRota90
=aGeo
.nRotationAngle
% 9000 ==0;
157 if (!bRota90
) { // there's seems to be a rounding error occurring: correct it
158 tools::Long a
=NormAngle36000(aGeo
.nRotationAngle
);
160 else if (a
<13500) a
=9000;
161 else if (a
<22500) a
=18000;
162 else if (a
<31500) a
=27000;
164 aGeo
.nRotationAngle
=a
;
167 if (bNotSheared
!=(aGeo
.nShearAngle
==0)) { // correct a rounding error occurring with Shear
173 ImpJustifyRect(maRect
);
177 if(bTextFrame
&& !getSdrModelFromSdrObject().IsPasteResize())
179 NbcAdjustTextFrameWidthAndHeight();
186 void SdrTextObj::NbcRotate(const Point
& rRef
, tools::Long nAngle
, double sn
, double cs
)
188 SetGlueReallyAbsolute(true);
189 tools::Long dx
=maRect
.Right()-maRect
.Left();
190 tools::Long dy
=maRect
.Bottom()-maRect
.Top();
191 Point
aP(maRect
.TopLeft());
192 RotatePoint(aP
,rRef
,sn
,cs
);
193 maRect
.SetLeft(aP
.X() );
194 maRect
.SetTop(aP
.Y() );
195 maRect
.SetRight(maRect
.Left()+dx
);
196 maRect
.SetBottom(maRect
.Top()+dy
);
197 if (aGeo
.nRotationAngle
==0) {
198 aGeo
.nRotationAngle
=NormAngle36000(nAngle
);
202 aGeo
.nRotationAngle
=NormAngle36000(aGeo
.nRotationAngle
+nAngle
);
206 NbcRotateGluePoints(rRef
,nAngle
,sn
,cs
);
207 SetGlueReallyAbsolute(false);
210 void SdrTextObj::NbcShear(const Point
& rRef
, tools::Long
/*nAngle*/, double tn
, bool bVShear
)
212 SetGlueReallyAbsolute(true);
214 // when this is a SdrPathObj, aRect may be uninitialized
215 tools::Polygon
aPol(Rect2Poly(maRect
.IsEmpty() ? GetSnapRect() : maRect
, aGeo
));
217 sal_uInt16 nPointCount
=aPol
.GetSize();
218 for (sal_uInt16 i
=0; i
<nPointCount
; i
++) {
219 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
221 Poly2Rect(aPol
,maRect
,aGeo
);
222 ImpJustifyRect(maRect
);
224 NbcAdjustTextFrameWidthAndHeight();
228 NbcShearGluePoints(rRef
,tn
,bVShear
);
229 SetGlueReallyAbsolute(false);
232 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
234 SetGlueReallyAbsolute(true);
235 bool bNotSheared
=aGeo
.nShearAngle
==0;
236 bool bRotate90
= false;
238 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
239 std::abs(rRef1
.X()-rRef2
.X())==std::abs(rRef1
.Y()-rRef2
.Y()))) {
240 bRotate90
=aGeo
.nRotationAngle
% 9000 ==0;
242 tools::Polygon
aPol(Rect2Poly(maRect
,aGeo
));
244 sal_uInt16 nPointCount
=aPol
.GetSize();
245 for (i
=0; i
<nPointCount
; i
++) {
246 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
248 // turn polygon and move it a little
249 tools::Polygon
aPol0(aPol
);
255 Poly2Rect(aPol
,maRect
,aGeo
);
258 bool bRota90
=aGeo
.nRotationAngle
% 9000 ==0;
259 if (bRotate90
&& !bRota90
) { // there's seems to be a rounding error occurring: correct it
260 tools::Long a
=NormAngle36000(aGeo
.nRotationAngle
);
262 else if (a
<13500) a
=9000;
263 else if (a
<22500) a
=18000;
264 else if (a
<31500) a
=27000;
266 aGeo
.nRotationAngle
=a
;
270 if (bNotSheared
!=(aGeo
.nShearAngle
==0)) { // correct a rounding error occurring with Shear
275 ImpJustifyRect(maRect
);
277 NbcAdjustTextFrameWidthAndHeight();
281 NbcMirrorGluePoints(rRef1
,rRef2
);
282 SetGlueReallyAbsolute(false);
286 SdrObjectUniquePtr
SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
288 SdrObjectUniquePtr pRetval
;
290 if(!ImpCanConvTextToCurve())
292 // suppress HelpTexts from PresObj's
297 const drawinglayer::primitive2d::Primitive2DContainer
& xSequence(GetViewContact().getViewIndependentPrimitive2DContainer());
299 if(!xSequence
.empty())
301 // create an extractor with neutral ViewInformation
302 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
303 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
305 // extract text as polygons
306 aExtractor
.process(xSequence
);
309 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
310 const sal_uInt32
nResultCount(rResult
.size());
314 // prepare own target
315 SdrObjGroup
* pGroup
= new SdrObjGroup(getSdrModelFromSdrObject());
316 SdrObjList
* pObjectList
= pGroup
->GetSubList();
319 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
321 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
322 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
324 if(aPolyPolygon
.count())
326 // take care of wanted polygon type
329 if(aPolyPolygon
.areControlPointsUsed())
331 aPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon
);
336 if(!aPolyPolygon
.areControlPointsUsed())
338 aPolyPolygon
= basegfx::utils::expandToCurve(aPolyPolygon
);
342 // create ItemSet with object attributes
343 SfxItemSet
aAttributeSet(GetObjectItemSet());
344 SdrPathObj
* pPathObj
= nullptr;
346 // always clear objectshadow; this is included in the extraction
347 aAttributeSet
.Put(makeSdrShadowItem(false));
349 if(rCandidate
.getIsFilled())
352 aAttributeSet
.Put(XFillColorItem(OUString(), Color(rCandidate
.getBColor())));
353 aAttributeSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
354 aAttributeSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
356 // create filled SdrPathObj
357 pPathObj
= new SdrPathObj(
358 getSdrModelFromSdrObject(),
365 aAttributeSet
.Put(XLineColorItem(OUString(), Color(rCandidate
.getBColor())));
366 aAttributeSet
.Put(XLineStyleItem(drawing::LineStyle_SOLID
));
367 aAttributeSet
.Put(XLineWidthItem(0));
368 aAttributeSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
370 // create line SdrPathObj
371 pPathObj
= new SdrPathObj(
372 getSdrModelFromSdrObject(),
377 // copy basic information from original
378 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
379 pPathObj
->NbcSetLayer(GetLayer());
380 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
382 // apply prepared ItemSet and add to target
383 pPathObj
->SetMergedItemSet(aAttributeSet
);
384 pObjectList
->InsertObject(pPathObj
);
388 // postprocess; if no result and/or only one object, simplify
389 if(!pObjectList
->GetObjCount())
391 // always use SdrObject::Free(...) for SdrObjects (!)
392 SdrObject
* pTemp(pGroup
);
393 SdrObject::Free(pTemp
);
395 else if(1 == pObjectList
->GetObjCount())
397 pRetval
.reset(pObjectList
->RemoveObject(0));
399 // always use SdrObject::Free(...) for SdrObjects (!)
400 SdrObject
* pTemp(pGroup
);
401 SdrObject::Free(pTemp
);
405 pRetval
.reset(pGroup
);
414 SdrObjectUniquePtr
SdrTextObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
418 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
424 bool SdrTextObj::ImpCanConvTextToCurve() const
426 return !IsOutlText();
429 SdrPathObjUniquePtr
SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, bool bClosed
, bool bBezier
) const
431 SdrObjKind ePathKind
= bClosed
? OBJ_PATHFILL
: OBJ_PATHLINE
;
432 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
437 aB2DPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
438 ePathKind
= bClosed
? OBJ_POLY
: OBJ_PLIN
;
441 SdrPathObjUniquePtr
pPathObj(new SdrPathObj(
442 getSdrModelFromSdrObject(),
448 // create bezier curves
449 pPathObj
->SetPathPoly(basegfx::utils::expandToCurve(pPathObj
->GetPathPoly()));
452 pPathObj
->ImpSetAnchorPos(aAnchor
);
453 pPathObj
->NbcSetLayer(GetLayer());
454 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
455 pPathObj
->ClearMergedItem();
456 pPathObj
->SetMergedItemSet(GetObjectItemSet());
457 pPathObj
->GetProperties().BroadcastItemChange(aC
);
458 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
463 SdrObjectUniquePtr
SdrTextObj::ImpConvertAddText(SdrObjectUniquePtr pObj
, bool bBezier
) const
465 if(!ImpCanConvTextToCurve())
470 SdrObjectUniquePtr pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
482 if(pText
->IsGroupObject())
484 // is already group object, add partial shape in front
485 SdrObjList
* pOL
=pText
->GetSubList();
486 pOL
->InsertObject(pObj
.release(),0);
492 // not yet a group, create one and add partial and new shapes
493 std::unique_ptr
<SdrObjGroup
, SdrObjectFreeOp
> pGrp(new SdrObjGroup(getSdrModelFromSdrObject()));
494 SdrObjList
* pOL
=pGrp
->GetSubList();
495 pOL
->InsertObject(pObj
.release());
496 pOL
->InsertObject(pText
.release());
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */