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>
27 #include <svx/svdmodel.hxx>
28 #include <editeng/editdata.hxx>
29 #include <editeng/outliner.hxx>
30 #include <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
);
65 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize()))
67 NbcAdjustTextFrameWidthAndHeight();
75 const Rectangle
& SdrTextObj::GetLogicRect() const
80 void SdrTextObj::NbcSetLogicRect(const Rectangle
& rRect
)
82 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
83 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
84 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
85 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
86 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
87 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
89 ImpJustifyRect(aRect
);
96 NbcAdjustTextFrameWidthAndHeight();
102 long SdrTextObj::GetRotateAngle() const
104 return aGeo
.nDrehWink
;
107 long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
109 return aGeo
.nShearWink
;
112 void SdrTextObj::NbcMove(const Size
& rSiz
)
114 MoveRect(aRect
,rSiz
);
115 MoveRect(aOutRect
,rSiz
);
116 MoveRect(maSnapRect
,rSiz
);
120 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
122 bool bNoShearMerk
=aGeo
.nShearWink
==0;
123 bool bRota90Merk
=bNoShearMerk
&& aGeo
.nDrehWink
% 9000 ==0;
124 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
125 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
126 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
127 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
128 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
129 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
130 if (bXMirr
|| bYMirr
) {
131 Point
aRef1(GetSnapRect().Center());
135 NbcMirrorGluePoints(aRef1
,aRef2
);
140 NbcMirrorGluePoints(aRef1
,aRef2
);
144 if (aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0) {
145 ResizeRect(aRect
,rRef
,xFact
,yFact
);
148 aRect
.Move(aRect
.Right()-aRect
.Left(),aRect
.Bottom()-aRect
.Top());
149 aGeo
.nDrehWink
=18000;
155 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
157 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
159 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
164 // turn polygon and move it a little
174 Poly2Rect(aPol
, aRect
, aGeo
);
178 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
179 if (!bRota90
) { // there's seems to be a rounding error occurring: correct it
180 long a
=NormAngle360(aGeo
.nDrehWink
);
182 else if (a
<13500) a
=9000;
183 else if (a
<22500) a
=18000;
184 else if (a
<31500) a
=27000;
189 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
195 ImpJustifyRect(aRect
);
197 long nTWdt1
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
198 long nTHgt1
=aRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
203 if(bTextFrame
&& (!pModel
|| !pModel
->IsPasteResize()))
205 NbcAdjustTextFrameWidthAndHeight();
212 void SdrTextObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
214 SetGlueReallyAbsolute(true);
215 long dx
=aRect
.Right()-aRect
.Left();
216 long dy
=aRect
.Bottom()-aRect
.Top();
217 Point
aP(aRect
.TopLeft());
218 RotatePoint(aP
,rRef
,sn
,cs
);
221 aRect
.Right()=aRect
.Left()+dx
;
222 aRect
.Bottom()=aRect
.Top()+dy
;
223 if (aGeo
.nDrehWink
==0) {
224 aGeo
.nDrehWink
=NormAngle360(nWink
);
228 aGeo
.nDrehWink
=NormAngle360(aGeo
.nDrehWink
+nWink
);
232 NbcRotateGluePoints(rRef
,nWink
,sn
,cs
);
233 SetGlueReallyAbsolute(false);
236 void SdrTextObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
238 SetGlueReallyAbsolute(true);
240 // when this is a SdrPathObj, aRect may be uninitialized
241 Polygon
aPol(Rect2Poly(aRect
.IsEmpty() ? GetSnapRect() : aRect
, aGeo
));
243 sal_uInt16 nPointCount
=aPol
.GetSize();
244 for (sal_uInt16 i
=0; i
<nPointCount
; i
++) {
245 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
247 Poly2Rect(aPol
,aRect
,aGeo
);
248 ImpJustifyRect(aRect
);
250 NbcAdjustTextFrameWidthAndHeight();
254 NbcShearGluePoints(rRef
,nWink
,tn
,bVShear
);
255 SetGlueReallyAbsolute(false);
258 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
260 SetGlueReallyAbsolute(true);
261 bool bNoShearMerk
=aGeo
.nShearWink
==0;
262 bool bRota90Merk
= false;
264 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
265 std::abs(rRef1
.X()-rRef2
.X())==std::abs(rRef1
.Y()-rRef2
.Y()))) {
266 bRota90Merk
=aGeo
.nDrehWink
% 9000 ==0;
268 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
270 sal_uInt16 nPntAnz
=aPol
.GetSize();
271 for (i
=0; i
<nPntAnz
; i
++) {
272 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
274 // turn polygon and move it a little
281 Poly2Rect(aPol
,aRect
,aGeo
);
284 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
285 if (bRota90Merk
&& !bRota90
) { // there's seems to be a rounding error occurring: correct it
286 long a
=NormAngle360(aGeo
.nDrehWink
);
288 else if (a
<13500) a
=9000;
289 else if (a
<22500) a
=18000;
290 else if (a
<31500) a
=27000;
296 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
301 ImpJustifyRect(aRect
);
303 NbcAdjustTextFrameWidthAndHeight();
307 NbcMirrorGluePoints(rRef1
,rRef2
);
308 SetGlueReallyAbsolute(false);
313 SdrObject
* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
315 SdrObject
* pRetval
= 0;
317 if(!ImpCanConvTextToCurve())
319 // suppress HelpTexts from PresObj's
324 const drawinglayer::primitive2d::Primitive2DSequence
xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
326 if(xSequence
.hasElements())
328 // create an extractor with neutral ViewInformation
329 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
330 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
332 // extract text as polygons
333 aExtractor
.process(xSequence
);
336 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
337 const sal_uInt32
nResultCount(rResult
.size());
341 // prepare own target
342 SdrObjGroup
* pGroup
= new SdrObjGroup();
343 SdrObjList
* pObjectList
= pGroup
->GetSubList();
346 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
348 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
349 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
351 if(aPolyPolygon
.count())
353 // take care of wanted polygon type
356 if(aPolyPolygon
.areControlPointsUsed())
358 aPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon
);
363 if(!aPolyPolygon
.areControlPointsUsed())
365 aPolyPolygon
= basegfx::tools::expandToCurve(aPolyPolygon
);
369 // create ItemSet with object attributes
370 SfxItemSet
aAttributeSet(GetObjectItemSet());
371 SdrPathObj
* pPathObj
= 0;
373 // always clear objectshadow; this is included in the extraction
374 aAttributeSet
.Put(SdrShadowItem(false));
376 if(rCandidate
.getIsFilled())
379 aAttributeSet
.Put(XFillColorItem(OUString(), Color(rCandidate
.getBColor())));
380 aAttributeSet
.Put(XLineStyleItem(XLINE_NONE
));
381 aAttributeSet
.Put(XFillStyleItem(XFILL_SOLID
));
383 // create filled SdrPathObj
384 pPathObj
= new SdrPathObj(OBJ_PATHFILL
, aPolyPolygon
);
389 aAttributeSet
.Put(XLineColorItem(OUString(), Color(rCandidate
.getBColor())));
390 aAttributeSet
.Put(XLineStyleItem(XLINE_SOLID
));
391 aAttributeSet
.Put(XLineWidthItem(0));
392 aAttributeSet
.Put(XFillStyleItem(XFILL_NONE
));
394 // create line SdrPathObj
395 pPathObj
= new SdrPathObj(OBJ_PATHLINE
, aPolyPolygon
);
398 // copy basic information from original
399 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
400 pPathObj
->NbcSetLayer(GetLayer());
404 pPathObj
->SetModel(GetModel());
405 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
408 // apply prepared ItemSet and add to target
409 pPathObj
->SetMergedItemSet(aAttributeSet
);
410 pObjectList
->InsertObject(pPathObj
);
414 // postprocess; if no result and/or only one object, simplify
415 if(!pObjectList
->GetObjCount())
419 else if(1 == pObjectList
->GetObjCount())
421 pRetval
= pObjectList
->RemoveObject(0);
436 SdrObject
* SdrTextObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
440 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
446 bool SdrTextObj::ImpCanConvTextToCurve() const
448 return !IsOutlText();
451 SdrObject
* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, bool bClosed
, bool bBezier
, bool bNoSetAttr
) const
453 SdrObjKind ePathKind
= bClosed
? OBJ_PATHFILL
: OBJ_PATHLINE
;
454 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
459 aB2DPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
460 ePathKind
= bClosed
? OBJ_POLY
: OBJ_PLIN
;
463 SdrPathObj
* pPathObj
= new SdrPathObj(ePathKind
, aB2DPolyPolygon
);
467 // create bezier curves
468 pPathObj
->SetPathPoly(basegfx::tools::expandToCurve(pPathObj
->GetPathPoly()));
473 pPathObj
->ImpSetAnchorPos(aAnchor
);
474 pPathObj
->NbcSetLayer(SdrLayerID(GetLayer()));
478 pPathObj
->SetModel(pModel
);
482 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
484 pPathObj
->ClearMergedItem();
485 pPathObj
->SetMergedItemSet(GetObjectItemSet());
486 pPathObj
->GetProperties().BroadcastItemChange(aC
);
487 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
495 SdrObject
* SdrTextObj::ImpConvertAddText(SdrObject
* pObj
, bool bBezier
) const
497 if(!ImpCanConvTextToCurve())
502 SdrObject
* pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
514 if(pText
->IsGroupObject())
516 // is already group object, add partial shape in front
517 SdrObjList
* pOL
=pText
->GetSubList();
518 pOL
->InsertObject(pObj
,0);
524 // not yet a group, create one and add partial and new shapes
525 SdrObjGroup
* pGrp
=new SdrObjGroup
;
526 SdrObjList
* pOL
=pGrp
->GetSubList();
527 pOL
->InsertObject(pObj
);
528 pOL
->InsertObject(pText
);
534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */