Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / svdraw / svdotxtr.cxx
blob25997de5c3af94883608148302e90d4c651ba058
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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()));
52 } else {
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;
59 aRect=rRect;
60 ImpJustifyRect(aRect);
62 // #115391#
63 AdaptTextMinSize();
65 if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize()))
67 NbcAdjustTextFrameWidthAndHeight();
70 ImpCheckShear();
71 SetRectsDirty();
75 const Rectangle& SdrTextObj::GetLogicRect() const
77 return aRect;
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;
88 aRect=rRect;
89 ImpJustifyRect(aRect);
91 // #115391#
92 AdaptTextMinSize();
94 if(bTextFrame)
96 NbcAdjustTextFrameWidthAndHeight();
99 SetRectsDirty();
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);
117 SetRectsDirty(true);
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());
132 if (bXMirr) {
133 Point aRef2(aRef1);
134 aRef2.Y()++;
135 NbcMirrorGluePoints(aRef1,aRef2);
137 if (bYMirr) {
138 Point aRef2(aRef1);
139 aRef2.X()++;
140 NbcMirrorGluePoints(aRef1,aRef2);
144 if (aGeo.nDrehWink==0 && aGeo.nShearWink==0) {
145 ResizeRect(aRect,rRef,xFact,yFact);
146 if (bYMirr) {
147 aRect.Justify();
148 aRect.Move(aRect.Right()-aRect.Left(),aRect.Bottom()-aRect.Top());
149 aGeo.nDrehWink=18000;
150 aGeo.RecalcSinCos();
153 else
155 Polygon aPol(Rect2Poly(aRect,aGeo));
157 for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
159 ResizePoint(aPol[a], rRef, xFact, yFact);
162 if(bXMirr != bYMirr)
164 // turn polygon and move it a little
165 Polygon aPol0(aPol);
167 aPol[0] = aPol0[1];
168 aPol[1] = aPol0[0];
169 aPol[2] = aPol0[3];
170 aPol[3] = aPol0[2];
171 aPol[4] = aPol0[1];
174 Poly2Rect(aPol, aRect, aGeo);
177 if (bRota90Merk) {
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);
181 if (a<4500) a=0;
182 else if (a<13500) a=9000;
183 else if (a<22500) a=18000;
184 else if (a<31500) a=27000;
185 else a=0;
186 aGeo.nDrehWink=a;
187 aGeo.RecalcSinCos();
189 if (bNoShearMerk!=(aGeo.nShearWink==0)) { // correct a rounding error occurring with Shear
190 aGeo.nShearWink=0;
191 aGeo.RecalcTan();
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;
200 // #115391#
201 AdaptTextMinSize();
203 if(bTextFrame && (!pModel || !pModel->IsPasteResize()))
205 NbcAdjustTextFrameWidthAndHeight();
208 ImpCheckShear();
209 SetRectsDirty();
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);
219 aRect.Left()=aP.X();
220 aRect.Top()=aP.Y();
221 aRect.Right()=aRect.Left()+dx;
222 aRect.Bottom()=aRect.Top()+dy;
223 if (aGeo.nDrehWink==0) {
224 aGeo.nDrehWink=NormAngle360(nWink);
225 aGeo.nSin=sn;
226 aGeo.nCos=cs;
227 } else {
228 aGeo.nDrehWink=NormAngle360(aGeo.nDrehWink+nWink);
229 aGeo.RecalcSinCos();
231 SetRectsDirty();
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);
249 if (bTextFrame) {
250 NbcAdjustTextFrameWidthAndHeight();
252 ImpCheckShear();
253 SetRectsDirty();
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;
263 if (bNoShearMerk &&
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));
269 sal_uInt16 i;
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
275 Polygon aPol0(aPol);
276 aPol[0]=aPol0[1];
277 aPol[1]=aPol0[0];
278 aPol[2]=aPol0[3];
279 aPol[3]=aPol0[2];
280 aPol[4]=aPol0[1];
281 Poly2Rect(aPol,aRect,aGeo);
283 if (bRota90Merk) {
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);
287 if (a<4500) a=0;
288 else if (a<13500) a=9000;
289 else if (a<22500) a=18000;
290 else if (a<31500) a=27000;
291 else a=0;
292 aGeo.nDrehWink=a;
293 aGeo.RecalcSinCos();
296 if (bNoShearMerk!=(aGeo.nShearWink==0)) { // correct a rounding error occurring with Shear
297 aGeo.nShearWink=0;
298 aGeo.RecalcTan();
301 ImpJustifyRect(aRect);
302 if (bTextFrame) {
303 NbcAdjustTextFrameWidthAndHeight();
305 ImpCheckShear();
306 SetRectsDirty();
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
320 return 0;
323 // get primitives
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);
335 // get results
336 const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
337 const sal_uInt32 nResultCount(rResult.size());
339 if(nResultCount)
341 // prepare own target
342 SdrObjGroup* pGroup = new SdrObjGroup();
343 SdrObjList* pObjectList = pGroup->GetSubList();
345 // process results
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
354 if(bToPoly)
356 if(aPolyPolygon.areControlPointsUsed())
358 aPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon);
361 else
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())
378 // set needed items
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);
386 else
388 // set needed items
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());
402 if(GetModel())
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())
417 delete pGroup;
419 else if(1 == pObjectList->GetObjCount())
421 pRetval = pObjectList->RemoveObject(0);
422 delete pGroup;
424 else
426 pRetval = pGroup;
431 return pRetval;
436 SdrObject* SdrTextObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
438 if(bAddText)
440 return ImpConvertContainedTextToSdrPathObjs(!bBezier);
443 return 0;
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);
456 // #i37011#
457 if(!bBezier)
459 aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon);
460 ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN;
463 SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon);
465 if(bBezier)
467 // create bezier curves
468 pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly()));
471 if(pPathObj)
473 pPathObj->ImpSetAnchorPos(aAnchor);
474 pPathObj->NbcSetLayer(SdrLayerID(GetLayer()));
476 if(pModel)
478 pPathObj->SetModel(pModel);
480 if(!bNoSetAttr)
482 sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
484 pPathObj->ClearMergedItem();
485 pPathObj->SetMergedItemSet(GetObjectItemSet());
486 pPathObj->GetProperties().BroadcastItemChange(aC);
487 pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
492 return pPathObj;
495 SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, bool bBezier) const
497 if(!ImpCanConvTextToCurve())
499 return pObj;
502 SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
504 if(!pText)
506 return pObj;
509 if(!pObj)
511 return pText;
514 if(pText->IsGroupObject())
516 // is already group object, add partial shape in front
517 SdrObjList* pOL=pText->GetSubList();
518 pOL->InsertObject(pObj,0);
520 return pText;
522 else
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);
530 return pGrp;
534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */