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/svdoutl.hxx>
26 #include <svx/svdpage.hxx> // for Convert
27 #include <svx/svdmodel.hxx> // for Convert
28 #include <editeng/editdata.hxx>
29 #include <editeng/outliner.hxx>
30 #include <svx/sdr/properties/itemsettools.hxx>
31 #include <svx/sdr/properties/properties.hxx>
32 #include <basegfx/polygon/b2dpolypolygontools.hxx>
33 #include <svl/itemset.hxx>
34 #include <svx/svditer.hxx>
35 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
36 #include <svx/sdr/contact/viewcontact.hxx>
37 #include <svx/xflclit.hxx>
38 #include <svx/xlnclit.hxx>
39 #include <svx/xlnwtit.hxx>
42 void SdrTextObj::NbcSetSnapRect(const Rectangle
& rRect
)
44 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0) {
45 Rectangle
aSR0(GetSnapRect());
46 long nWdt0
=aSR0
.Right()-aSR0
.Left();
47 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
48 long nWdt1
=rRect
.Right()-rRect
.Left();
49 long nHgt1
=rRect
.Bottom()-rRect
.Top();
50 SdrTextObj::NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
51 SdrTextObj::NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
53 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
54 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
55 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
56 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
57 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
58 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
60 ImpJustifyRect(aRect
);
61 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) {
62 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
63 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
64 NbcAdjustTextFrameWidthAndHeight();
71 const Rectangle
& SdrTextObj::GetLogicRect() const
76 void SdrTextObj::NbcSetLogicRect(const Rectangle
& rRect
)
78 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
79 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
80 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
81 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
82 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
83 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
85 ImpJustifyRect(aRect
);
87 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
88 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
89 NbcAdjustTextFrameWidthAndHeight();
94 long SdrTextObj::GetRotateAngle() const
96 return aGeo
.nDrehWink
;
99 long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
101 return aGeo
.nShearWink
;
104 void SdrTextObj::NbcMove(const Size
& rSiz
)
106 MoveRect(aRect
,rSiz
);
107 MoveRect(aOutRect
,rSiz
);
108 MoveRect(maSnapRect
,rSiz
);
109 SetRectsDirty(sal_True
);
112 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
114 bool bNoShearMerk
=aGeo
.nShearWink
==0;
115 bool bRota90Merk
=bNoShearMerk
&& aGeo
.nDrehWink
% 9000 ==0;
116 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
117 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
118 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
119 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
120 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
121 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
122 if (bXMirr
|| bYMirr
) {
123 Point
aRef1(GetSnapRect().Center());
127 NbcMirrorGluePoints(aRef1
,aRef2
);
132 NbcMirrorGluePoints(aRef1
,aRef2
);
136 if (aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0) {
137 ResizeRect(aRect
,rRef
,xFact
,yFact
);
140 aRect
.Move(aRect
.Right()-aRect
.Left(),aRect
.Bottom()-aRect
.Top());
141 aGeo
.nDrehWink
=18000;
147 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
149 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
151 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
156 // turn polygon and move it a little
166 Poly2Rect(aPol
, aRect
, aGeo
);
170 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
171 if (!bRota90
) { // there's seems to be a rounding error occurring: correct it
172 long a
=NormAngle360(aGeo
.nDrehWink
);
174 else if (a
<13500) a
=9000;
175 else if (a
<22500) a
=18000;
176 else if (a
<31500) a
=27000;
181 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
187 ImpJustifyRect(aRect
);
188 long nTWdt1
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
189 long nTHgt1
=aRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
190 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) {
191 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
192 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
193 NbcAdjustTextFrameWidthAndHeight();
199 void SdrTextObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
201 SetGlueReallyAbsolute(sal_True
);
202 long dx
=aRect
.Right()-aRect
.Left();
203 long dy
=aRect
.Bottom()-aRect
.Top();
204 Point
aP(aRect
.TopLeft());
205 RotatePoint(aP
,rRef
,sn
,cs
);
208 aRect
.Right()=aRect
.Left()+dx
;
209 aRect
.Bottom()=aRect
.Top()+dy
;
210 if (aGeo
.nDrehWink
==0) {
211 aGeo
.nDrehWink
=NormAngle360(nWink
);
215 aGeo
.nDrehWink
=NormAngle360(aGeo
.nDrehWink
+nWink
);
219 NbcRotateGluePoints(rRef
,nWink
,sn
,cs
);
220 SetGlueReallyAbsolute(sal_False
);
223 void SdrTextObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
225 SetGlueReallyAbsolute(sal_True
);
227 // when this is a SdrPathObj, aRect may be uninitialized
228 Polygon
aPol(Rect2Poly(aRect
.IsEmpty() ? GetSnapRect() : aRect
, aGeo
));
230 sal_uInt16 nPointCount
=aPol
.GetSize();
231 for (sal_uInt16 i
=0; i
<nPointCount
; i
++) {
232 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
234 Poly2Rect(aPol
,aRect
,aGeo
);
235 ImpJustifyRect(aRect
);
237 NbcAdjustTextFrameWidthAndHeight();
241 NbcShearGluePoints(rRef
,nWink
,tn
,bVShear
);
242 SetGlueReallyAbsolute(sal_False
);
245 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
247 SetGlueReallyAbsolute(sal_True
);
248 bool bNoShearMerk
=aGeo
.nShearWink
==0;
249 bool bRota90Merk
= false;
251 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
252 std::abs(rRef1
.X()-rRef2
.X())==std::abs(rRef1
.Y()-rRef2
.Y()))) {
253 bRota90Merk
=aGeo
.nDrehWink
% 9000 ==0;
255 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
257 sal_uInt16 nPntAnz
=aPol
.GetSize();
258 for (i
=0; i
<nPntAnz
; i
++) {
259 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
261 // turn polygon and move it a little
268 Poly2Rect(aPol
,aRect
,aGeo
);
271 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
272 if (bRota90Merk
&& !bRota90
) { // there's seems to be a rounding error occurring: correct it
273 long a
=NormAngle360(aGeo
.nDrehWink
);
275 else if (a
<13500) a
=9000;
276 else if (a
<22500) a
=18000;
277 else if (a
<31500) a
=27000;
283 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
288 ImpJustifyRect(aRect
);
290 NbcAdjustTextFrameWidthAndHeight();
294 NbcMirrorGluePoints(rRef1
,rRef2
);
295 SetGlueReallyAbsolute(sal_False
);
298 //////////////////////////////////////////////////////////////////////////////
300 SdrObject
* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
302 SdrObject
* pRetval
= 0;
304 if(!ImpCanConvTextToCurve())
306 // suppress HelpTexts from PresObj's
311 const drawinglayer::primitive2d::Primitive2DSequence
xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
313 if(xSequence
.hasElements())
315 // create an extractor with neutral ViewInformation
316 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
317 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
319 // extract text as polygons
320 aExtractor
.process(xSequence
);
323 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
324 const sal_uInt32
nResultCount(rResult
.size());
328 // prepare own target
329 SdrObjGroup
* pGroup
= new SdrObjGroup();
330 SdrObjList
* pObjectList
= pGroup
->GetSubList();
333 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
335 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
336 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
338 if(aPolyPolygon
.count())
340 // take care of wanted polygon type
343 if(aPolyPolygon
.areControlPointsUsed())
345 aPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon
);
350 if(!aPolyPolygon
.areControlPointsUsed())
352 aPolyPolygon
= basegfx::tools::expandToCurve(aPolyPolygon
);
356 // create ItemSet with object attributes
357 SfxItemSet
aAttributeSet(GetObjectItemSet());
358 SdrPathObj
* pPathObj
= 0;
360 // always clear objectshadow; this is included in the extraction
361 aAttributeSet
.Put(SdrShadowItem(false));
363 if(rCandidate
.getIsFilled())
366 aAttributeSet
.Put(XFillColorItem(String(), Color(rCandidate
.getBColor())));
367 aAttributeSet
.Put(XLineStyleItem(XLINE_NONE
));
368 aAttributeSet
.Put(XFillStyleItem(XFILL_SOLID
));
370 // create filled SdrPathObj
371 pPathObj
= new SdrPathObj(OBJ_PATHFILL
, aPolyPolygon
);
376 aAttributeSet
.Put(XLineColorItem(String(), Color(rCandidate
.getBColor())));
377 aAttributeSet
.Put(XLineStyleItem(XLINE_SOLID
));
378 aAttributeSet
.Put(XLineWidthItem(0));
379 aAttributeSet
.Put(XFillStyleItem(XFILL_NONE
));
381 // create line SdrPathObj
382 pPathObj
= new SdrPathObj(OBJ_PATHLINE
, aPolyPolygon
);
385 // copy basic information from original
386 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
387 pPathObj
->NbcSetLayer(GetLayer());
391 pPathObj
->SetModel(GetModel());
392 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
395 // apply prepared ItemSet and add to target
396 pPathObj
->SetMergedItemSet(aAttributeSet
);
397 pObjectList
->InsertObject(pPathObj
);
401 // postprocess; if no result and/or only one object, simplify
402 if(!pObjectList
->GetObjCount())
406 else if(1 == pObjectList
->GetObjCount())
408 pRetval
= pObjectList
->RemoveObject(0);
421 //////////////////////////////////////////////////////////////////////////////
423 SdrObject
* SdrTextObj::DoConvertToPolyObj(sal_Bool bBezier
, bool bAddText
) const
427 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
433 bool SdrTextObj::ImpCanConvTextToCurve() const
435 return !IsOutlText();
438 SdrObject
* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, sal_Bool bClosed
, sal_Bool bBezier
, sal_Bool bNoSetAttr
) const
440 SdrObjKind ePathKind
= bClosed
? OBJ_PATHFILL
: OBJ_PATHLINE
;
441 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
446 aB2DPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
447 ePathKind
= bClosed
? OBJ_POLY
: OBJ_PLIN
;
450 SdrPathObj
* pPathObj
= new SdrPathObj(ePathKind
, aB2DPolyPolygon
);
454 // create bezier curves
455 pPathObj
->SetPathPoly(basegfx::tools::expandToCurve(pPathObj
->GetPathPoly()));
460 pPathObj
->ImpSetAnchorPos(aAnchor
);
461 pPathObj
->NbcSetLayer(SdrLayerID(GetLayer()));
465 pPathObj
->SetModel(pModel
);
469 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
471 pPathObj
->ClearMergedItem();
472 pPathObj
->SetMergedItemSet(GetObjectItemSet());
473 pPathObj
->GetProperties().BroadcastItemChange(aC
);
474 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), sal_True
);
482 SdrObject
* SdrTextObj::ImpConvertAddText(SdrObject
* pObj
, bool bBezier
) const
484 if(!ImpCanConvTextToCurve())
489 SdrObject
* pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
501 if(pText
->IsGroupObject())
503 // is already group object, add partial shape in front
504 SdrObjList
* pOL
=pText
->GetSubList();
505 pOL
->InsertObject(pObj
,0);
511 // not yet a group, create one and add partial and new shapes
512 SdrObjGroup
* pGrp
=new SdrObjGroup
;
513 SdrObjList
* pOL
=pGrp
->GetSubList();
514 pOL
->InsertObject(pObj
);
515 pOL
->InsertObject(pText
);
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */