xref: /AOO41X/main/svx/source/svdraw/svdotxtr.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 
27 #include <svx/svdotext.hxx>
28 #include "svx/svditext.hxx"
29 #include <svx/svdtrans.hxx>
30 #include <svx/svdogrp.hxx>
31 #include <svx/svdopath.hxx>
32 #include <svx/svdoutl.hxx>
33 #include <svx/svdpage.hxx>   // fuer Convert
34 #include <svx/svdmodel.hxx>  // fuer Convert
35 #include <editeng/outliner.hxx>
36 #include <svx/sdr/properties/itemsettools.hxx>
37 #include <svx/sdr/properties/properties.hxx>
38 #include <basegfx/polygon/b2dpolypolygontools.hxx>
39 #include <svl/itemset.hxx>
40 #include <svx/svditer.hxx>
41 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
42 #include <svx/sdr/contact/viewcontact.hxx>
43 #include <svx/xflclit.hxx>
44 #include <svx/xlnclit.hxx>
45 #include <svx/xlnwtit.hxx>
46 
47 ////////////////////////////////////////////////////////////////////////////////////////////////////
48 //
49 //  @@@@@@ @@@@@ @@   @@ @@@@@@  @@@@  @@@@@  @@@@@@
50 //    @@   @@    @@@ @@@   @@   @@  @@ @@  @@     @@
51 //    @@   @@     @@@@@    @@   @@  @@ @@  @@     @@
52 //    @@   @@@@    @@@     @@   @@  @@ @@@@@      @@
53 //    @@   @@     @@@@@    @@   @@  @@ @@  @@     @@
54 //    @@   @@    @@@ @@@   @@   @@  @@ @@  @@ @@  @@
55 //    @@   @@@@@ @@   @@   @@    @@@@  @@@@@   @@@@
56 //
57 //  Transformationen
58 //
59 ////////////////////////////////////////////////////////////////////////////////////////////////////
60 
61 void SdrTextObj::NbcSetSnapRect(const Rectangle& rRect)
62 {
63     if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) {
64         Rectangle aSR0(GetSnapRect());
65         long nWdt0=aSR0.Right()-aSR0.Left();
66         long nHgt0=aSR0.Bottom()-aSR0.Top();
67         long nWdt1=rRect.Right()-rRect.Left();
68         long nHgt1=rRect.Bottom()-rRect.Top();
69         SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
70         SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
71     } else {
72         long nHDist=GetTextLeftDistance()+GetTextRightDistance();
73         long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
74         long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
75         long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
76         long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
77         long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
78         aRect=rRect;
79         ImpJustifyRect(aRect);
80         if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize())) { // #51139#
81             if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1);
82             if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1);
83             if (GetFitToSize()==SDRTEXTFIT_RESIZEATTR) {
84                 NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0));
85             }
86             NbcAdjustTextFrameWidthAndHeight();
87         }
88         ImpCheckShear();
89         SetRectsDirty();
90     }
91 }
92 
93 const Rectangle& SdrTextObj::GetLogicRect() const
94 {
95     return aRect;
96 }
97 
98 void SdrTextObj::NbcSetLogicRect(const Rectangle& rRect)
99 {
100     long nHDist=GetTextLeftDistance()+GetTextRightDistance();
101     long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
102     long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
103     long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
104     long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
105     long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
106     aRect=rRect;
107     ImpJustifyRect(aRect);
108     if (bTextFrame) {
109         if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1);
110         if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1);
111         if (GetFitToSize()==SDRTEXTFIT_RESIZEATTR) {
112             NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0));
113         }
114         NbcAdjustTextFrameWidthAndHeight();
115     }
116     SetRectsDirty();
117 }
118 
119 long SdrTextObj::GetRotateAngle() const
120 {
121     return aGeo.nDrehWink;
122 }
123 
124 long SdrTextObj::GetShearAngle(FASTBOOL /*bVertical*/) const
125 {
126     return aGeo.nShearWink;
127 }
128 
129 void SdrTextObj::NbcMove(const Size& rSiz)
130 {
131     MoveRect(aRect,rSiz);
132     MoveRect(aOutRect,rSiz);
133     MoveRect(maSnapRect,rSiz);
134     SetRectsDirty(sal_True);
135 }
136 
137 void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
138 {
139     FASTBOOL bNoShearMerk=aGeo.nShearWink==0;
140     FASTBOOL bRota90Merk=bNoShearMerk && aGeo.nDrehWink % 9000 ==0;
141     long nHDist=GetTextLeftDistance()+GetTextRightDistance();
142     long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
143     long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
144     long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
145     FASTBOOL bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
146     FASTBOOL bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
147     if (bXMirr || bYMirr) {
148         Point aRef1(GetSnapRect().Center());
149         if (bXMirr) {
150             Point aRef2(aRef1);
151             aRef2.Y()++;
152             NbcMirrorGluePoints(aRef1,aRef2);
153         }
154         if (bYMirr) {
155             Point aRef2(aRef1);
156             aRef2.X()++;
157             NbcMirrorGluePoints(aRef1,aRef2);
158         }
159     }
160 
161     if (aGeo.nDrehWink==0 && aGeo.nShearWink==0) {
162         ResizeRect(aRect,rRef,xFact,yFact);
163         if (bYMirr) {
164             aRect.Justify();
165             aRect.Move(aRect.Right()-aRect.Left(),aRect.Bottom()-aRect.Top());
166             aGeo.nDrehWink=18000;
167             aGeo.RecalcSinCos();
168         }
169     }
170     else
171     {
172         // #100663# aRect is NOT initialized for lines (polgon objects with two
173         // exceptionally handled points). Thus, after this call the text rotaion is
174         // gone. This error must be present since day one of this old drawing layer.
175         // It's astonishing that noone discovered it earlier.
176         // Polygon aPol(Rect2Poly(aRect,aGeo));
177         // Polygon aPol(Rect2Poly(GetSnapRect(), aGeo));
178 
179         // #101412# go back to old method, side effects are impossible
180         // to calculate.
181         Polygon aPol(Rect2Poly(aRect,aGeo));
182 
183         for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
184         {
185              ResizePoint(aPol[a], rRef, xFact, yFact);
186         }
187 
188         if(bXMirr != bYMirr)
189         {
190             // Polygon wenden und etwas schieben
191             Polygon aPol0(aPol);
192 
193             aPol[0] = aPol0[1];
194             aPol[1] = aPol0[0];
195             aPol[2] = aPol0[3];
196             aPol[3] = aPol0[2];
197             aPol[4] = aPol0[1];
198         }
199 
200         Poly2Rect(aPol, aRect, aGeo);
201     }
202 
203     if (bRota90Merk) {
204         FASTBOOL bRota90=aGeo.nDrehWink % 9000 ==0;
205         if (!bRota90) { // Scheinbar Rundungsfehler: Korregieren
206             long a=NormAngle360(aGeo.nDrehWink);
207             if (a<4500) a=0;
208             else if (a<13500) a=9000;
209             else if (a<22500) a=18000;
210             else if (a<31500) a=27000;
211             else a=0;
212             aGeo.nDrehWink=a;
213             aGeo.RecalcSinCos();
214         }
215         if (bNoShearMerk!=(aGeo.nShearWink==0)) { // Shear ggf. korregieren wg. Rundungsfehler
216             aGeo.nShearWink=0;
217             aGeo.RecalcTan();
218         }
219     }
220 
221     ImpJustifyRect(aRect);
222     long nTWdt1=aRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
223     long nTHgt1=aRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
224     if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize())) { // #51139#
225         if (nTWdt0!=nTWdt1 && IsAutoGrowWidth() ) NbcSetMinTextFrameWidth(nTWdt1);
226         if (nTHgt0!=nTHgt1 && IsAutoGrowHeight()) NbcSetMinTextFrameHeight(nTHgt1);
227         if (GetFitToSize()==SDRTEXTFIT_RESIZEATTR) {
228             NbcResizeTextAttributes(Fraction(nTWdt1,nTWdt0),Fraction(nTHgt1,nTHgt0));
229         }
230         NbcAdjustTextFrameWidthAndHeight();
231     }
232     ImpCheckShear();
233     SetRectsDirty();
234 }
235 
236 void SdrTextObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
237 {
238     SetGlueReallyAbsolute(sal_True);
239     long dx=aRect.Right()-aRect.Left();
240     long dy=aRect.Bottom()-aRect.Top();
241     Point aP(aRect.TopLeft());
242     RotatePoint(aP,rRef,sn,cs);
243     aRect.Left()=aP.X();
244     aRect.Top()=aP.Y();
245     aRect.Right()=aRect.Left()+dx;
246     aRect.Bottom()=aRect.Top()+dy;
247     if (aGeo.nDrehWink==0) {
248         aGeo.nDrehWink=NormAngle360(nWink);
249         aGeo.nSin=sn;
250         aGeo.nCos=cs;
251     } else {
252         aGeo.nDrehWink=NormAngle360(aGeo.nDrehWink+nWink);
253         aGeo.RecalcSinCos();
254     }
255     SetRectsDirty();
256     NbcRotateGluePoints(rRef,nWink,sn,cs);
257     SetGlueReallyAbsolute(sal_False);
258 }
259 
260 void SdrTextObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
261 {
262     SetGlueReallyAbsolute(sal_True);
263 
264     // #75889# when this is a SdrPathObj aRect maybe not initialized
265     Polygon aPol(Rect2Poly(aRect.IsEmpty() ? GetSnapRect() : aRect, aGeo));
266 
267     sal_uInt16 nPointCount=aPol.GetSize();
268     for (sal_uInt16 i=0; i<nPointCount; i++) {
269          ShearPoint(aPol[i],rRef,tn,bVShear);
270     }
271     Poly2Rect(aPol,aRect,aGeo);
272     ImpJustifyRect(aRect);
273     if (bTextFrame) {
274         NbcAdjustTextFrameWidthAndHeight();
275     }
276     ImpCheckShear();
277     SetRectsDirty();
278     NbcShearGluePoints(rRef,nWink,tn,bVShear);
279     SetGlueReallyAbsolute(sal_False);
280 }
281 
282 void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
283 {
284     SetGlueReallyAbsolute(sal_True);
285     FASTBOOL bNoShearMerk=aGeo.nShearWink==0;
286     FASTBOOL bRota90Merk=sal_False;
287     if (bNoShearMerk &&
288         (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
289          Abs(rRef1.X()-rRef2.X())==Abs(rRef1.Y()-rRef2.Y()))) {
290         bRota90Merk=aGeo.nDrehWink % 9000 ==0;
291     }
292     Polygon aPol(Rect2Poly(aRect,aGeo));
293     sal_uInt16 i;
294     sal_uInt16 nPntAnz=aPol.GetSize();
295     for (i=0; i<nPntAnz; i++) {
296          MirrorPoint(aPol[i],rRef1,rRef2);
297     }
298     // Polygon wenden und etwas schieben
299     Polygon aPol0(aPol);
300     aPol[0]=aPol0[1];
301     aPol[1]=aPol0[0];
302     aPol[2]=aPol0[3];
303     aPol[3]=aPol0[2];
304     aPol[4]=aPol0[1];
305     Poly2Rect(aPol,aRect,aGeo);
306 
307     if (bRota90Merk) {
308         FASTBOOL bRota90=aGeo.nDrehWink % 9000 ==0;
309         if (bRota90Merk && !bRota90) { // Scheinbar Rundungsfehler: Korregieren
310             long a=NormAngle360(aGeo.nDrehWink);
311             if (a<4500) a=0;
312             else if (a<13500) a=9000;
313             else if (a<22500) a=18000;
314             else if (a<31500) a=27000;
315             else a=0;
316             aGeo.nDrehWink=a;
317             aGeo.RecalcSinCos();
318         }
319     }
320     if (bNoShearMerk!=(aGeo.nShearWink==0)) { // Shear ggf. korregieren wg. Rundungsfehler
321         aGeo.nShearWink=0;
322         aGeo.RecalcTan();
323     }
324 
325     ImpJustifyRect(aRect);
326     if (bTextFrame) {
327         NbcAdjustTextFrameWidthAndHeight();
328     }
329     ImpCheckShear();
330     SetRectsDirty();
331     NbcMirrorGluePoints(rRef1,rRef2);
332     SetGlueReallyAbsolute(sal_False);
333 }
334 
335 //////////////////////////////////////////////////////////////////////////////
336 
337 SdrObject* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
338 {
339     SdrObject* pRetval = 0;
340 
341     if(!ImpCanConvTextToCurve())
342     {
343         // suppress HelpTexts from PresObj's
344         return 0;
345     }
346 
347     // get primitives
348     const drawinglayer::primitive2d::Primitive2DSequence xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
349 
350     if(xSequence.hasElements())
351     {
352         // create an extractor with neutral ViewInformation
353         const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
354         drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
355 
356         // extract text as polygons
357         aExtractor.process(xSequence);
358 
359         // get results
360         const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
361         const sal_uInt32 nResultCount(rResult.size());
362 
363         if(nResultCount)
364         {
365             // prepare own target
366             SdrObjGroup* pGroup = new SdrObjGroup();
367             SdrObjList* pObjectList = pGroup->GetSubList();
368 
369             // process results
370             for(sal_uInt32 a(0); a < nResultCount; a++)
371             {
372                 const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
373                 basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon());
374 
375                 if(aPolyPolygon.count())
376                 {
377                     // take care of wanted polygon type
378                     if(bToPoly)
379                     {
380                         if(aPolyPolygon.areControlPointsUsed())
381                         {
382                             aPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon);
383                         }
384                     }
385                     else
386                     {
387                         if(!aPolyPolygon.areControlPointsUsed())
388                         {
389                             aPolyPolygon = basegfx::tools::expandToCurve(aPolyPolygon);
390                         }
391                     }
392 
393                     // create ItemSet with object attributes
394                     SfxItemSet aAttributeSet(GetObjectItemSet());
395                     SdrPathObj* pPathObj = 0;
396 
397                     // always clear objectshadow; this is included in the extraction
398                     aAttributeSet.Put(SdrShadowItem(false));
399 
400                     if(rCandidate.getIsFilled())
401                     {
402                         // set needed items
403                         aAttributeSet.Put(XFillColorItem(String(), Color(rCandidate.getBColor())));
404                         aAttributeSet.Put(XLineStyleItem(XLINE_NONE));
405                         aAttributeSet.Put(XFillStyleItem(XFILL_SOLID));
406 
407                         // create filled SdrPathObj
408                         pPathObj = new SdrPathObj(OBJ_PATHFILL, aPolyPolygon);
409                     }
410                     else
411                     {
412                         // set needed items
413                         aAttributeSet.Put(XLineColorItem(String(), Color(rCandidate.getBColor())));
414                         aAttributeSet.Put(XLineStyleItem(XLINE_SOLID));
415                         aAttributeSet.Put(XLineWidthItem(0));
416                         aAttributeSet.Put(XFillStyleItem(XFILL_NONE));
417 
418                         // create line SdrPathObj
419                         pPathObj = new SdrPathObj(OBJ_PATHLINE, aPolyPolygon);
420                     }
421 
422                     // copy basic information from original
423                     pPathObj->ImpSetAnchorPos(GetAnchorPos());
424                     pPathObj->NbcSetLayer(GetLayer());
425 
426                     if(GetModel())
427                     {
428                         pPathObj->SetModel(GetModel());
429                         pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
430                     }
431 
432                     // apply prepared ItemSet and add to target
433                     pPathObj->SetMergedItemSet(aAttributeSet);
434                     pObjectList->InsertObject(pPathObj);
435                 }
436             }
437 
438             // postprocess; if no result and/or only one object, simplify
439             if(!pObjectList->GetObjCount())
440             {
441                 delete pGroup;
442             }
443             else if(1 == pObjectList->GetObjCount())
444             {
445                 pRetval = pObjectList->RemoveObject(0);
446                 delete pGroup;
447             }
448             else
449             {
450                 pRetval = pGroup;
451             }
452         }
453     }
454 
455     return pRetval;
456 }
457 
458 //////////////////////////////////////////////////////////////////////////////
459 
460 SdrObject* SdrTextObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
461 {
462     if(bAddText)
463     {
464         return ImpConvertContainedTextToSdrPathObjs(!bBezier);
465     }
466 
467     return 0;
468 }
469 
470 bool SdrTextObj::ImpCanConvTextToCurve() const
471 {
472     return !IsOutlText();
473 }
474 
475 SdrObject* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, sal_Bool bClosed, sal_Bool bBezier, sal_Bool bNoSetAttr) const
476 {
477     SdrObjKind ePathKind = bClosed ? OBJ_PATHFILL : OBJ_PATHLINE;
478     basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
479 
480     // #i37011#
481     if(!bBezier)
482     {
483         aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon);
484         ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN;
485     }
486 
487     SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon);
488 
489     if(bBezier)
490     {
491         // create bezier curves
492         pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly()));
493     }
494 
495     if(pPathObj)
496     {
497         pPathObj->ImpSetAnchorPos(aAnchor);
498         pPathObj->NbcSetLayer(SdrLayerID(GetLayer()));
499 
500         if(pModel)
501         {
502             pPathObj->SetModel(pModel);
503 
504             if(!bNoSetAttr)
505             {
506                 sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
507 
508                 pPathObj->ClearMergedItem();
509                 pPathObj->SetMergedItemSet(GetObjectItemSet());
510                 pPathObj->GetProperties().BroadcastItemChange(aC);
511                 pPathObj->NbcSetStyleSheet(GetStyleSheet(), sal_True);
512             }
513         }
514     }
515 
516     return pPathObj;
517 }
518 
519 SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, FASTBOOL bBezier) const
520 {
521     if(!ImpCanConvTextToCurve())
522     {
523         return pObj;
524     }
525 
526     SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
527 
528     if(!pText)
529     {
530         return pObj;
531     }
532 
533     if(!pObj)
534     {
535         return pText;
536     }
537 
538     if(pText->IsGroupObject())
539     {
540         // is already group object, add partial shape in front
541         SdrObjList* pOL=pText->GetSubList();
542         pOL->InsertObject(pObj,0);
543 
544         return pText;
545     }
546     else
547     {
548         // not yet a group, create one and add partial and new shapes
549         SdrObjGroup* pGrp=new SdrObjGroup;
550         SdrObjList* pOL=pGrp->GetSubList();
551         pOL->InsertObject(pObj);
552         pOL->InsertObject(pText);
553 
554         return pGrp;
555     }
556 }
557 
558 //////////////////////////////////////////////////////////////////////////////
559 // eof
560