1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <svx/svdotext.hxx>
31 #include "svx/svditext.hxx"
32 #include <svx/svdtrans.hxx>
33 #include <svx/svdogrp.hxx>
34 #include <svx/svdopath.hxx>
35 #include <svx/svdoutl.hxx>
36 #include <svx/svdpage.hxx> // for Convert
37 #include <svx/svdmodel.hxx> // for Convert
38 #include <editeng/outliner.hxx>
39 #include <svx/sdr/properties/itemsettools.hxx>
40 #include <svx/sdr/properties/properties.hxx>
41 #include <basegfx/polygon/b2dpolypolygontools.hxx>
42 #include <svl/itemset.hxx>
43 #include <svx/svditer.hxx>
44 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
45 #include <svx/sdr/contact/viewcontact.hxx>
46 #include <svx/xflclit.hxx>
47 #include <svx/xlnclit.hxx>
48 #include <svx/xlnwtit.hxx>
51 void SdrTextObj::NbcSetSnapRect(const Rectangle
& rRect
)
53 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0) {
54 Rectangle
aSR0(GetSnapRect());
55 long nWdt0
=aSR0
.Right()-aSR0
.Left();
56 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
57 long nWdt1
=rRect
.Right()-rRect
.Left();
58 long nHgt1
=rRect
.Bottom()-rRect
.Top();
59 SdrTextObj::NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
60 SdrTextObj::NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
62 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
63 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
64 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
65 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
66 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
67 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
69 ImpJustifyRect(aRect
);
70 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) {
71 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
72 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
73 NbcAdjustTextFrameWidthAndHeight();
80 const Rectangle
& SdrTextObj::GetLogicRect() const
85 void SdrTextObj::NbcSetLogicRect(const Rectangle
& rRect
)
87 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
88 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
89 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
90 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
91 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
92 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
94 ImpJustifyRect(aRect
);
96 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
97 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
98 NbcAdjustTextFrameWidthAndHeight();
103 long SdrTextObj::GetRotateAngle() const
105 return aGeo
.nDrehWink
;
108 long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
110 return aGeo
.nShearWink
;
113 void SdrTextObj::NbcMove(const Size
& rSiz
)
115 MoveRect(aRect
,rSiz
);
116 MoveRect(aOutRect
,rSiz
);
117 MoveRect(maSnapRect
,rSiz
);
118 SetRectsDirty(sal_True
);
121 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
123 bool bNoShearMerk
=aGeo
.nShearWink
==0;
124 bool bRota90Merk
=bNoShearMerk
&& aGeo
.nDrehWink
% 9000 ==0;
125 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
126 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
127 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
128 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
129 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
130 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
131 if (bXMirr
|| bYMirr
) {
132 Point
aRef1(GetSnapRect().Center());
136 NbcMirrorGluePoints(aRef1
,aRef2
);
141 NbcMirrorGluePoints(aRef1
,aRef2
);
145 if (aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0) {
146 ResizeRect(aRect
,rRef
,xFact
,yFact
);
149 aRect
.Move(aRect
.Right()-aRect
.Left(),aRect
.Bottom()-aRect
.Top());
150 aGeo
.nDrehWink
=18000;
156 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
158 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
160 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
165 // turn polygon and move it a little
175 Poly2Rect(aPol
, aRect
, aGeo
);
179 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
180 if (!bRota90
) { // there's seems to be a rounding error occurring: correct it
181 long a
=NormAngle360(aGeo
.nDrehWink
);
183 else if (a
<13500) a
=9000;
184 else if (a
<22500) a
=18000;
185 else if (a
<31500) a
=27000;
190 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
196 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;
199 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) {
200 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
201 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
202 NbcAdjustTextFrameWidthAndHeight();
208 void SdrTextObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
210 SetGlueReallyAbsolute(sal_True
);
211 long dx
=aRect
.Right()-aRect
.Left();
212 long dy
=aRect
.Bottom()-aRect
.Top();
213 Point
aP(aRect
.TopLeft());
214 RotatePoint(aP
,rRef
,sn
,cs
);
217 aRect
.Right()=aRect
.Left()+dx
;
218 aRect
.Bottom()=aRect
.Top()+dy
;
219 if (aGeo
.nDrehWink
==0) {
220 aGeo
.nDrehWink
=NormAngle360(nWink
);
224 aGeo
.nDrehWink
=NormAngle360(aGeo
.nDrehWink
+nWink
);
228 NbcRotateGluePoints(rRef
,nWink
,sn
,cs
);
229 SetGlueReallyAbsolute(sal_False
);
232 void SdrTextObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
234 SetGlueReallyAbsolute(sal_True
);
236 // when this is a SdrPathObj, aRect may be uninitialized
237 Polygon
aPol(Rect2Poly(aRect
.IsEmpty() ? GetSnapRect() : aRect
, aGeo
));
239 sal_uInt16 nPointCount
=aPol
.GetSize();
240 for (sal_uInt16 i
=0; i
<nPointCount
; i
++) {
241 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
243 Poly2Rect(aPol
,aRect
,aGeo
);
244 ImpJustifyRect(aRect
);
246 NbcAdjustTextFrameWidthAndHeight();
250 NbcShearGluePoints(rRef
,nWink
,tn
,bVShear
);
251 SetGlueReallyAbsolute(sal_False
);
254 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
256 SetGlueReallyAbsolute(sal_True
);
257 bool bNoShearMerk
=aGeo
.nShearWink
==0;
258 bool bRota90Merk
= false;
260 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
261 Abs(rRef1
.X()-rRef2
.X())==Abs(rRef1
.Y()-rRef2
.Y()))) {
262 bRota90Merk
=aGeo
.nDrehWink
% 9000 ==0;
264 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
266 sal_uInt16 nPntAnz
=aPol
.GetSize();
267 for (i
=0; i
<nPntAnz
; i
++) {
268 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
270 // turn polygon and move it a little
277 Poly2Rect(aPol
,aRect
,aGeo
);
280 bool bRota90
=aGeo
.nDrehWink
% 9000 ==0;
281 if (bRota90Merk
&& !bRota90
) { // there's seems to be a rounding error occurring: correct it
282 long a
=NormAngle360(aGeo
.nDrehWink
);
284 else if (a
<13500) a
=9000;
285 else if (a
<22500) a
=18000;
286 else if (a
<31500) a
=27000;
292 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // correct a rounding error occurring with Shear
297 ImpJustifyRect(aRect
);
299 NbcAdjustTextFrameWidthAndHeight();
303 NbcMirrorGluePoints(rRef1
,rRef2
);
304 SetGlueReallyAbsolute(sal_False
);
307 //////////////////////////////////////////////////////////////////////////////
309 SdrObject
* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
311 SdrObject
* pRetval
= 0;
313 if(!ImpCanConvTextToCurve())
315 // suppress HelpTexts from PresObj's
320 const drawinglayer::primitive2d::Primitive2DSequence
xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
322 if(xSequence
.hasElements())
324 // create an extractor with neutral ViewInformation
325 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
326 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
328 // extract text as polygons
329 aExtractor
.process(xSequence
);
332 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
333 const sal_uInt32
nResultCount(rResult
.size());
337 // prepare own target
338 SdrObjGroup
* pGroup
= new SdrObjGroup();
339 SdrObjList
* pObjectList
= pGroup
->GetSubList();
342 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
344 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
345 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
347 if(aPolyPolygon
.count())
349 // take care of wanted polygon type
352 if(aPolyPolygon
.areControlPointsUsed())
354 aPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon
);
359 if(!aPolyPolygon
.areControlPointsUsed())
361 aPolyPolygon
= basegfx::tools::expandToCurve(aPolyPolygon
);
365 // create ItemSet with object attributes
366 SfxItemSet
aAttributeSet(GetObjectItemSet());
367 SdrPathObj
* pPathObj
= 0;
369 // always clear objectshadow; this is included in the extraction
370 aAttributeSet
.Put(SdrShadowItem(false));
372 if(rCandidate
.getIsFilled())
375 aAttributeSet
.Put(XFillColorItem(String(), Color(rCandidate
.getBColor())));
376 aAttributeSet
.Put(XLineStyleItem(XLINE_NONE
));
377 aAttributeSet
.Put(XFillStyleItem(XFILL_SOLID
));
379 // create filled SdrPathObj
380 pPathObj
= new SdrPathObj(OBJ_PATHFILL
, aPolyPolygon
);
385 aAttributeSet
.Put(XLineColorItem(String(), Color(rCandidate
.getBColor())));
386 aAttributeSet
.Put(XLineStyleItem(XLINE_SOLID
));
387 aAttributeSet
.Put(XLineWidthItem(0));
388 aAttributeSet
.Put(XFillStyleItem(XFILL_NONE
));
390 // create line SdrPathObj
391 pPathObj
= new SdrPathObj(OBJ_PATHLINE
, aPolyPolygon
);
394 // copy basic information from original
395 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
396 pPathObj
->NbcSetLayer(GetLayer());
400 pPathObj
->SetModel(GetModel());
401 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
404 // apply prepared ItemSet and add to target
405 pPathObj
->SetMergedItemSet(aAttributeSet
);
406 pObjectList
->InsertObject(pPathObj
);
410 // postprocess; if no result and/or only one object, simplify
411 if(!pObjectList
->GetObjCount())
415 else if(1 == pObjectList
->GetObjCount())
417 pRetval
= pObjectList
->RemoveObject(0);
430 //////////////////////////////////////////////////////////////////////////////
432 SdrObject
* SdrTextObj::DoConvertToPolyObj(sal_Bool bBezier
) const
434 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
437 bool SdrTextObj::ImpCanConvTextToCurve() const
439 return !IsOutlText();
442 SdrObject
* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, sal_Bool bClosed
, sal_Bool bBezier
, sal_Bool bNoSetAttr
) const
444 SdrObjKind ePathKind
= bClosed
? OBJ_PATHFILL
: OBJ_PATHLINE
;
445 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
450 aB2DPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
451 ePathKind
= bClosed
? OBJ_POLY
: OBJ_PLIN
;
454 SdrPathObj
* pPathObj
= new SdrPathObj(ePathKind
, aB2DPolyPolygon
);
458 // create bezier curves
459 pPathObj
->SetPathPoly(basegfx::tools::expandToCurve(pPathObj
->GetPathPoly()));
464 pPathObj
->ImpSetAnchorPos(aAnchor
);
465 pPathObj
->NbcSetLayer(SdrLayerID(GetLayer()));
469 pPathObj
->SetModel(pModel
);
473 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
475 pPathObj
->ClearMergedItem();
476 pPathObj
->SetMergedItemSet(GetObjectItemSet());
477 pPathObj
->GetProperties().BroadcastItemChange(aC
);
478 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), sal_True
);
486 SdrObject
* SdrTextObj::ImpConvertAddText(SdrObject
* pObj
, bool bBezier
) const
488 if(!ImpCanConvTextToCurve())
493 SdrObject
* pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
505 if(pText
->IsGroupObject())
507 // is already group object, add partial shape in front
508 SdrObjList
* pOL
=pText
->GetSubList();
509 pOL
->InsertObject(pObj
,0);
515 // not yet a group, create one and add partial and new shapes
516 SdrObjGroup
* pGrp
=new SdrObjGroup
;
517 SdrObjList
* pOL
=pGrp
->GetSubList();
518 pOL
->InsertObject(pObj
);
519 pOL
->InsertObject(pText
);
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */