1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdotxtr.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <svx/svdotext.hxx>
35 #include "svditext.hxx"
36 #include <svx/svdtrans.hxx>
37 #include <svx/svdogrp.hxx>
38 #include <svx/svdopath.hxx>
39 #include <svx/svdoutl.hxx>
40 #include <svx/svdpage.hxx> // fuer Convert
41 #include <svx/svdmodel.hxx> // fuer Convert
42 #include <svx/outliner.hxx>
43 #include <svx/sdr/properties/itemsettools.hxx>
44 #include <svx/sdr/properties/properties.hxx>
45 #include <basegfx/polygon/b2dpolypolygontools.hxx>
46 #include <svtools/itemset.hxx>
47 #include <svditer.hxx>
48 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
49 #include <svx/sdr/contact/viewcontact.hxx>
50 #include <svx/xflclit.hxx>
51 #include <svx/xlnclit.hxx>
52 #include <svx/xlnwtit.hxx>
54 ////////////////////////////////////////////////////////////////////////////////////////////////////
56 // @@@@@@ @@@@@ @@ @@ @@@@@@ @@@@ @@@@@ @@@@@@
57 // @@ @@ @@@ @@@ @@ @@ @@ @@ @@ @@
58 // @@ @@ @@@@@ @@ @@ @@ @@ @@ @@
59 // @@ @@@@ @@@ @@ @@ @@ @@@@@ @@
60 // @@ @@ @@@@@ @@ @@ @@ @@ @@ @@
61 // @@ @@ @@@ @@@ @@ @@ @@ @@ @@ @@ @@
62 // @@ @@@@@ @@ @@ @@ @@@@ @@@@@ @@@@
66 ////////////////////////////////////////////////////////////////////////////////////////////////////
68 void SdrTextObj::NbcSetSnapRect(const Rectangle
& rRect
)
70 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0) {
71 Rectangle
aSR0(GetSnapRect());
72 long nWdt0
=aSR0
.Right()-aSR0
.Left();
73 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
74 long nWdt1
=rRect
.Right()-rRect
.Left();
75 long nHgt1
=rRect
.Bottom()-rRect
.Top();
76 SdrTextObj::NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
77 SdrTextObj::NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
79 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
80 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
81 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
82 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
83 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
84 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
86 ImpJustifyRect(aRect
);
87 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) { // #51139#
88 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
89 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
90 NbcAdjustTextFrameWidthAndHeight();
97 const Rectangle
& SdrTextObj::GetLogicRect() const
102 void SdrTextObj::NbcSetLogicRect(const Rectangle
& rRect
)
104 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
105 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
106 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
107 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
108 long nTWdt1
=rRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
109 long nTHgt1
=rRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
111 ImpJustifyRect(aRect
);
113 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
114 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
115 NbcAdjustTextFrameWidthAndHeight();
120 long SdrTextObj::GetRotateAngle() const
122 return aGeo
.nDrehWink
;
125 long SdrTextObj::GetShearAngle(FASTBOOL
/*bVertical*/) const
127 return aGeo
.nShearWink
;
130 void SdrTextObj::NbcMove(const Size
& rSiz
)
132 MoveRect(aRect
,rSiz
);
133 MoveRect(aOutRect
,rSiz
);
134 MoveRect(maSnapRect
,rSiz
);
135 SetRectsDirty(sal_True
);
138 void SdrTextObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
140 FASTBOOL bNoShearMerk
=aGeo
.nShearWink
==0;
141 FASTBOOL bRota90Merk
=bNoShearMerk
&& aGeo
.nDrehWink
% 9000 ==0;
142 long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
143 long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
144 long nTWdt0
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt0
<0) nTWdt0
=0;
145 long nTHgt0
=aRect
.GetHeight()-1-nVDist
; if (nTHgt0
<0) nTHgt0
=0;
146 FASTBOOL bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
147 FASTBOOL bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
148 if (bXMirr
|| bYMirr
) {
149 Point
aRef1(GetSnapRect().Center());
153 NbcMirrorGluePoints(aRef1
,aRef2
);
158 NbcMirrorGluePoints(aRef1
,aRef2
);
162 if (aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0) {
163 ResizeRect(aRect
,rRef
,xFact
,yFact
);
166 aRect
.Move(aRect
.Right()-aRect
.Left(),aRect
.Bottom()-aRect
.Top());
167 aGeo
.nDrehWink
=18000;
173 // #100663# aRect is NOT initialized for lines (polgon objects with two
174 // exceptionally handled points). Thus, after this call the text rotaion is
175 // gone. This error must be present since day one of this old drawing layer.
176 // It's astonishing that noone discovered it earlier.
177 // Polygon aPol(Rect2Poly(aRect,aGeo));
178 // Polygon aPol(Rect2Poly(GetSnapRect(), aGeo));
180 // #101412# go back to old method, side effects are impossible
182 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
184 for(sal_uInt16
a(0); a
< aPol
.GetSize(); a
++)
186 ResizePoint(aPol
[a
], rRef
, xFact
, yFact
);
191 // Polygon wenden und etwas schieben
201 Poly2Rect(aPol
, aRect
, aGeo
);
205 FASTBOOL bRota90
=aGeo
.nDrehWink
% 9000 ==0;
206 if (!bRota90
) { // Scheinbar Rundungsfehler: Korregieren
207 long a
=NormAngle360(aGeo
.nDrehWink
);
209 else if (a
<13500) a
=9000;
210 else if (a
<22500) a
=18000;
211 else if (a
<31500) a
=27000;
216 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // Shear ggf. korregieren wg. Rundungsfehler
222 ImpJustifyRect(aRect
);
223 long nTWdt1
=aRect
.GetWidth ()-1-nHDist
; if (nTWdt1
<0) nTWdt1
=0;
224 long nTHgt1
=aRect
.GetHeight()-1-nVDist
; if (nTHgt1
<0) nTHgt1
=0;
225 if (bTextFrame
&& (pModel
==NULL
|| !pModel
->IsPasteResize())) { // #51139#
226 if (nTWdt0
!=nTWdt1
&& IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1
);
227 if (nTHgt0
!=nTHgt1
&& IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1
);
228 NbcAdjustTextFrameWidthAndHeight();
234 void SdrTextObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
236 SetGlueReallyAbsolute(TRUE
);
237 long dx
=aRect
.Right()-aRect
.Left();
238 long dy
=aRect
.Bottom()-aRect
.Top();
239 Point
aP(aRect
.TopLeft());
240 RotatePoint(aP
,rRef
,sn
,cs
);
243 aRect
.Right()=aRect
.Left()+dx
;
244 aRect
.Bottom()=aRect
.Top()+dy
;
245 if (aGeo
.nDrehWink
==0) {
246 aGeo
.nDrehWink
=NormAngle360(nWink
);
250 aGeo
.nDrehWink
=NormAngle360(aGeo
.nDrehWink
+nWink
);
254 NbcRotateGluePoints(rRef
,nWink
,sn
,cs
);
255 SetGlueReallyAbsolute(FALSE
);
258 void SdrTextObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, FASTBOOL bVShear
)
260 SetGlueReallyAbsolute(TRUE
);
262 // #75889# when this is a SdrPathObj aRect maybe not initialized
263 Polygon
aPol(Rect2Poly(aRect
.IsEmpty() ? GetSnapRect() : aRect
, aGeo
));
265 USHORT nPointCount
=aPol
.GetSize();
266 for (USHORT i
=0; i
<nPointCount
; i
++) {
267 ShearPoint(aPol
[i
],rRef
,tn
,bVShear
);
269 Poly2Rect(aPol
,aRect
,aGeo
);
270 ImpJustifyRect(aRect
);
272 NbcAdjustTextFrameWidthAndHeight();
276 NbcShearGluePoints(rRef
,nWink
,tn
,bVShear
);
277 SetGlueReallyAbsolute(FALSE
);
280 void SdrTextObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
282 SetGlueReallyAbsolute(TRUE
);
283 FASTBOOL bNoShearMerk
=aGeo
.nShearWink
==0;
284 FASTBOOL bRota90Merk
=FALSE
;
286 (rRef1
.X()==rRef2
.X() || rRef1
.Y()==rRef2
.Y() ||
287 Abs(rRef1
.X()-rRef2
.X())==Abs(rRef1
.Y()-rRef2
.Y()))) {
288 bRota90Merk
=aGeo
.nDrehWink
% 9000 ==0;
290 Polygon
aPol(Rect2Poly(aRect
,aGeo
));
292 USHORT nPntAnz
=aPol
.GetSize();
293 for (i
=0; i
<nPntAnz
; i
++) {
294 MirrorPoint(aPol
[i
],rRef1
,rRef2
);
296 // Polygon wenden und etwas schieben
303 Poly2Rect(aPol
,aRect
,aGeo
);
306 FASTBOOL bRota90
=aGeo
.nDrehWink
% 9000 ==0;
307 if (bRota90Merk
&& !bRota90
) { // Scheinbar Rundungsfehler: Korregieren
308 long a
=NormAngle360(aGeo
.nDrehWink
);
310 else if (a
<13500) a
=9000;
311 else if (a
<22500) a
=18000;
312 else if (a
<31500) a
=27000;
318 if (bNoShearMerk
!=(aGeo
.nShearWink
==0)) { // Shear ggf. korregieren wg. Rundungsfehler
323 ImpJustifyRect(aRect
);
325 NbcAdjustTextFrameWidthAndHeight();
329 NbcMirrorGluePoints(rRef1
,rRef2
);
330 SetGlueReallyAbsolute(FALSE
);
333 //////////////////////////////////////////////////////////////////////////////
335 SdrObject
* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly
) const
337 SdrObject
* pRetval
= 0;
339 if(!ImpCanConvTextToCurve())
341 // suppress HelpTexts from PresObj's
346 const drawinglayer::primitive2d::Primitive2DSequence
xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
348 if(xSequence
.hasElements())
350 // create an extractor with neutral ViewInformation
351 const drawinglayer::geometry::ViewInformation2D
aViewInformation2D(0);
352 drawinglayer::processor2d::TextAsPolygonExtractor2D
aExtractor(aViewInformation2D
);
354 // extract text as polygons
355 aExtractor
.process(xSequence
);
358 const drawinglayer::processor2d::TextAsPolygonDataNodeVector
& rResult
= aExtractor
.getTarget();
359 const sal_uInt32
nResultCount(rResult
.size());
363 // prepare own target
364 SdrObjGroup
* pGroup
= new SdrObjGroup();
365 SdrObjList
* pObjectList
= pGroup
->GetSubList();
368 for(sal_uInt32
a(0); a
< nResultCount
; a
++)
370 const drawinglayer::processor2d::TextAsPolygonDataNode
& rCandidate
= rResult
[a
];
371 basegfx::B2DPolyPolygon
aPolyPolygon(rCandidate
.getB2DPolyPolygon());
373 if(aPolyPolygon
.count())
375 // take care of wanted polygon type
378 if(aPolyPolygon
.areControlPointsUsed())
380 aPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon
);
385 if(!aPolyPolygon
.areControlPointsUsed())
387 aPolyPolygon
= basegfx::tools::expandToCurve(aPolyPolygon
);
391 // create ItemSet with object attributes
392 SfxItemSet
aAttributeSet(GetObjectItemSet());
393 SdrPathObj
* pPathObj
= 0;
395 // always clear objectshadow; this is included in the extraction
396 aAttributeSet
.Put(SdrShadowItem(false));
398 if(rCandidate
.getIsFilled())
401 aAttributeSet
.Put(XFillColorItem(String(), Color(rCandidate
.getBColor())));
402 aAttributeSet
.Put(XLineStyleItem(XLINE_NONE
));
403 aAttributeSet
.Put(XFillStyleItem(XFILL_SOLID
));
405 // create filled SdrPathObj
406 pPathObj
= new SdrPathObj(OBJ_PATHFILL
, aPolyPolygon
);
411 aAttributeSet
.Put(XLineColorItem(String(), Color(rCandidate
.getBColor())));
412 aAttributeSet
.Put(XLineStyleItem(XLINE_SOLID
));
413 aAttributeSet
.Put(XLineWidthItem(0));
414 aAttributeSet
.Put(XFillStyleItem(XFILL_NONE
));
416 // create line SdrPathObj
417 pPathObj
= new SdrPathObj(OBJ_PATHLINE
, aPolyPolygon
);
420 // copy basic information from original
421 pPathObj
->ImpSetAnchorPos(GetAnchorPos());
422 pPathObj
->NbcSetLayer(GetLayer());
426 pPathObj
->SetModel(GetModel());
427 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), true);
430 // apply prepared ItemSet and add to target
431 pPathObj
->SetMergedItemSet(aAttributeSet
);
432 pObjectList
->InsertObject(pPathObj
);
436 // postprocess; if no result and/or only one object, simplify
437 if(!pObjectList
->GetObjCount())
441 else if(1 == pObjectList
->GetObjCount())
443 pRetval
= pObjectList
->RemoveObject(0);
456 //////////////////////////////////////////////////////////////////////////////
458 SdrObject
* SdrTextObj::DoConvertToPolyObj(BOOL bBezier
) const
460 return ImpConvertContainedTextToSdrPathObjs(!bBezier
);
463 bool SdrTextObj::ImpCanConvTextToCurve() const
465 return !IsOutlText();
468 SdrObject
* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon
& rPolyPolygon
, sal_Bool bClosed
, sal_Bool bBezier
, sal_Bool bNoSetAttr
) const
470 SdrObjKind ePathKind
= bClosed
? OBJ_PATHFILL
: OBJ_PATHLINE
;
471 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPolygon
);
476 aB2DPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon
);
477 ePathKind
= bClosed
? OBJ_POLY
: OBJ_PLIN
;
480 SdrPathObj
* pPathObj
= new SdrPathObj(ePathKind
, aB2DPolyPolygon
);
484 // create bezier curves
485 pPathObj
->SetPathPoly(basegfx::tools::expandToCurve(pPathObj
->GetPathPoly()));
490 pPathObj
->ImpSetAnchorPos(aAnchor
);
491 pPathObj
->NbcSetLayer(SdrLayerID(GetLayer()));
495 pPathObj
->SetModel(pModel
);
499 sdr::properties::ItemChangeBroadcaster
aC(*pPathObj
);
501 pPathObj
->ClearMergedItem();
502 pPathObj
->SetMergedItemSet(GetObjectItemSet());
503 pPathObj
->GetProperties().BroadcastItemChange(aC
);
504 pPathObj
->NbcSetStyleSheet(GetStyleSheet(), sal_True
);
512 SdrObject
* SdrTextObj::ImpConvertAddText(SdrObject
* pObj
, FASTBOOL bBezier
) const
514 if(!ImpCanConvTextToCurve())
519 SdrObject
* pText
= ImpConvertContainedTextToSdrPathObjs(!bBezier
);
531 if(pText
->IsGroupObject())
533 // is already group object, add partial shape in front
534 SdrObjList
* pOL
=pText
->GetSubList();
535 pOL
->InsertObject(pObj
,0);
541 // not yet a group, create one and add partial and new shapes
542 SdrObjGroup
* pGrp
=new SdrObjGroup
;
543 SdrObjList
* pOL
=pGrp
->GetSubList();
544 pOL
->InsertObject(pObj
);
545 pOL
->InsertObject(pText
);
551 //////////////////////////////////////////////////////////////////////////////