Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
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>
40 :
41 : using namespace com::sun::star;
42 :
43 44998 : void SdrTextObj::NbcSetSnapRect(const Rectangle& rRect)
44 : {
45 44998 : if (aGeo.nRotationAngle!=0 || aGeo.nShearAngle!=0)
46 : {
47 : // Either the rotation or shear angle exists.
48 8 : Rectangle aSR0(GetSnapRect());
49 8 : long nWdt0=aSR0.Right()-aSR0.Left();
50 8 : long nHgt0=aSR0.Bottom()-aSR0.Top();
51 8 : long nWdt1=rRect.Right()-rRect.Left();
52 8 : long nHgt1=rRect.Bottom()-rRect.Top();
53 8 : SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
54 8 : SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
55 : }
56 : else
57 : {
58 : // No rotation or shear.
59 :
60 44990 : maRect = rRect;
61 44990 : ImpJustifyRect(maRect);
62 :
63 : // #115391#
64 44990 : AdaptTextMinSize();
65 :
66 44990 : ImpCheckShear();
67 44990 : SetRectsDirty();
68 : }
69 44998 : }
70 :
71 344627 : const Rectangle& SdrTextObj::GetLogicRect() const
72 : {
73 344627 : return maRect;
74 : }
75 :
76 65651 : void SdrTextObj::NbcSetLogicRect(const Rectangle& rRect)
77 : {
78 65651 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
79 65651 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
80 65651 : long nTWdt0=maRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
81 65651 : long nTHgt0=maRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
82 65651 : long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
83 65651 : long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
84 65651 : maRect = rRect;
85 65651 : ImpJustifyRect(maRect);
86 :
87 : // #115391#
88 65651 : AdaptTextMinSize();
89 :
90 65651 : SetRectsDirty();
91 65651 : }
92 :
93 7724 : long SdrTextObj::GetRotateAngle() const
94 : {
95 7724 : return aGeo.nRotationAngle;
96 : }
97 :
98 1 : long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
99 : {
100 1 : return aGeo.nShearAngle;
101 : }
102 :
103 117250 : void SdrTextObj::NbcMove(const Size& rSiz)
104 : {
105 117250 : MoveRect(maRect,rSiz);
106 117250 : MoveRect(aOutRect,rSiz);
107 117250 : MoveRect(maSnapRect,rSiz);
108 117250 : SetRectsDirty(true);
109 117250 : }
110 :
111 38490 : void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
112 : {
113 38490 : bool bNoShearMerk=aGeo.nShearAngle==0;
114 38490 : bool bRota90Merk=bNoShearMerk && aGeo.nRotationAngle % 9000 ==0;
115 38490 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
116 38490 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
117 38490 : long nTWdt0=maRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
118 38490 : long nTHgt0=maRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
119 38490 : bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
120 38490 : bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
121 38490 : if (bXMirr || bYMirr) {
122 36260 : Point aRef1(GetSnapRect().Center());
123 36260 : if (bXMirr) {
124 36260 : Point aRef2(aRef1);
125 36260 : aRef2.Y()++;
126 36260 : NbcMirrorGluePoints(aRef1,aRef2);
127 : }
128 36260 : if (bYMirr) {
129 36260 : Point aRef2(aRef1);
130 36260 : aRef2.X()++;
131 36260 : NbcMirrorGluePoints(aRef1,aRef2);
132 : }
133 : }
134 :
135 38490 : if (aGeo.nRotationAngle==0 && aGeo.nShearAngle==0) {
136 19436 : ResizeRect(maRect,rRef,xFact,yFact);
137 38872 : if (bYMirr) {
138 18298 : maRect.Justify();
139 18298 : maRect.Move(maRect.Right()-maRect.Left(),maRect.Bottom()-maRect.Top());
140 18298 : aGeo.nRotationAngle=18000;
141 18298 : aGeo.RecalcSinCos();
142 : }
143 : }
144 : else
145 : {
146 19054 : Polygon aPol(Rect2Poly(maRect,aGeo));
147 :
148 114324 : for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
149 : {
150 95270 : ResizePoint(aPol[a], rRef, xFact, yFact);
151 : }
152 :
153 19054 : if(bXMirr != bYMirr)
154 : {
155 : // turn polygon and move it a little
156 0 : Polygon aPol0(aPol);
157 :
158 0 : aPol[0] = aPol0[1];
159 0 : aPol[1] = aPol0[0];
160 0 : aPol[2] = aPol0[3];
161 0 : aPol[3] = aPol0[2];
162 0 : aPol[4] = aPol0[1];
163 : }
164 :
165 19054 : Poly2Rect(aPol, maRect, aGeo);
166 : }
167 :
168 38490 : if (bRota90Merk) {
169 37760 : bool bRota90=aGeo.nRotationAngle % 9000 ==0;
170 37760 : if (!bRota90) { // there's seems to be a rounding error occurring: correct it
171 0 : long a=NormAngle360(aGeo.nRotationAngle);
172 0 : if (a<4500) a=0;
173 0 : else if (a<13500) a=9000;
174 0 : else if (a<22500) a=18000;
175 0 : else if (a<31500) a=27000;
176 0 : else a=0;
177 0 : aGeo.nRotationAngle=a;
178 0 : aGeo.RecalcSinCos();
179 : }
180 37760 : if (bNoShearMerk!=(aGeo.nShearAngle==0)) { // correct a rounding error occurring with Shear
181 17956 : aGeo.nShearAngle=0;
182 17956 : aGeo.RecalcTan();
183 : }
184 : }
185 :
186 38490 : ImpJustifyRect(maRect);
187 :
188 38490 : long nTWdt1=maRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
189 38490 : long nTHgt1=maRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
190 :
191 : // #115391#
192 38490 : AdaptTextMinSize();
193 :
194 38490 : if(bTextFrame && (!pModel || !pModel->IsPasteResize()))
195 : {
196 150 : NbcAdjustTextFrameWidthAndHeight();
197 : }
198 :
199 38490 : ImpCheckShear();
200 38490 : SetRectsDirty();
201 38490 : }
202 :
203 1784 : void SdrTextObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
204 : {
205 1784 : SetGlueReallyAbsolute(true);
206 1784 : long dx=maRect.Right()-maRect.Left();
207 1784 : long dy=maRect.Bottom()-maRect.Top();
208 1784 : Point aP(maRect.TopLeft());
209 1784 : RotatePoint(aP,rRef,sn,cs);
210 1784 : maRect.Left()=aP.X();
211 1784 : maRect.Top()=aP.Y();
212 1784 : maRect.Right()=maRect.Left()+dx;
213 1784 : maRect.Bottom()=maRect.Top()+dy;
214 1784 : if (aGeo.nRotationAngle==0) {
215 1719 : aGeo.nRotationAngle=NormAngle360(nAngle);
216 1719 : aGeo.nSin=sn;
217 1719 : aGeo.nCos=cs;
218 : } else {
219 65 : aGeo.nRotationAngle=NormAngle360(aGeo.nRotationAngle+nAngle);
220 65 : aGeo.RecalcSinCos();
221 : }
222 1784 : SetRectsDirty();
223 1784 : NbcRotateGluePoints(rRef,nAngle,sn,cs);
224 1784 : SetGlueReallyAbsolute(false);
225 1784 : }
226 :
227 2 : void SdrTextObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
228 : {
229 2 : SetGlueReallyAbsolute(true);
230 :
231 : // when this is a SdrPathObj, aRect may be uninitialized
232 2 : Polygon aPol(Rect2Poly(maRect.IsEmpty() ? GetSnapRect() : maRect, aGeo));
233 :
234 2 : sal_uInt16 nPointCount=aPol.GetSize();
235 12 : for (sal_uInt16 i=0; i<nPointCount; i++) {
236 10 : ShearPoint(aPol[i],rRef,tn,bVShear);
237 : }
238 2 : Poly2Rect(aPol,maRect,aGeo);
239 2 : ImpJustifyRect(maRect);
240 2 : if (bTextFrame) {
241 0 : NbcAdjustTextFrameWidthAndHeight();
242 : }
243 2 : ImpCheckShear();
244 2 : SetRectsDirty();
245 2 : NbcShearGluePoints(rRef,nAngle,tn,bVShear);
246 2 : SetGlueReallyAbsolute(false);
247 2 : }
248 :
249 413 : void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
250 : {
251 413 : SetGlueReallyAbsolute(true);
252 413 : bool bNoShearMerk=aGeo.nShearAngle==0;
253 413 : bool bRota90Merk = false;
254 1239 : if (bNoShearMerk &&
255 756 : (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
256 0 : std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
257 413 : bRota90Merk=aGeo.nRotationAngle % 9000 ==0;
258 : }
259 413 : Polygon aPol(Rect2Poly(maRect,aGeo));
260 : sal_uInt16 i;
261 413 : sal_uInt16 nPointCount=aPol.GetSize();
262 2478 : for (i=0; i<nPointCount; i++) {
263 2065 : MirrorPoint(aPol[i],rRef1,rRef2);
264 : }
265 : // turn polygon and move it a little
266 826 : Polygon aPol0(aPol);
267 413 : aPol[0]=aPol0[1];
268 413 : aPol[1]=aPol0[0];
269 413 : aPol[2]=aPol0[3];
270 413 : aPol[3]=aPol0[2];
271 413 : aPol[4]=aPol0[1];
272 413 : Poly2Rect(aPol,maRect,aGeo);
273 :
274 413 : if (bRota90Merk) {
275 390 : bool bRota90=aGeo.nRotationAngle % 9000 ==0;
276 390 : if (bRota90Merk && !bRota90) { // there's seems to be a rounding error occurring: correct it
277 0 : long a=NormAngle360(aGeo.nRotationAngle);
278 0 : if (a<4500) a=0;
279 0 : else if (a<13500) a=9000;
280 0 : else if (a<22500) a=18000;
281 0 : else if (a<31500) a=27000;
282 0 : else a=0;
283 0 : aGeo.nRotationAngle=a;
284 0 : aGeo.RecalcSinCos();
285 : }
286 : }
287 413 : if (bNoShearMerk!=(aGeo.nShearAngle==0)) { // correct a rounding error occurring with Shear
288 18 : aGeo.nShearAngle=0;
289 18 : aGeo.RecalcTan();
290 : }
291 :
292 413 : ImpJustifyRect(maRect);
293 413 : if (bTextFrame) {
294 10 : NbcAdjustTextFrameWidthAndHeight();
295 : }
296 413 : ImpCheckShear();
297 413 : SetRectsDirty();
298 413 : NbcMirrorGluePoints(rRef1,rRef2);
299 826 : SetGlueReallyAbsolute(false);
300 413 : }
301 :
302 :
303 :
304 26 : SdrObject* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
305 : {
306 26 : SdrObject* pRetval = 0;
307 :
308 26 : if(!ImpCanConvTextToCurve())
309 : {
310 : // suppress HelpTexts from PresObj's
311 0 : return 0;
312 : }
313 :
314 : // get primitives
315 26 : const drawinglayer::primitive2d::Primitive2DSequence xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
316 :
317 26 : if(xSequence.hasElements())
318 : {
319 : // create an extractor with neutral ViewInformation
320 26 : const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
321 52 : drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
322 :
323 : // extract text as polygons
324 26 : aExtractor.process(xSequence);
325 :
326 : // get results
327 26 : const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
328 26 : const sal_uInt32 nResultCount(rResult.size());
329 :
330 26 : if(nResultCount)
331 : {
332 : // prepare own target
333 0 : SdrObjGroup* pGroup = new SdrObjGroup();
334 0 : SdrObjList* pObjectList = pGroup->GetSubList();
335 :
336 : // process results
337 0 : for(sal_uInt32 a(0); a < nResultCount; a++)
338 : {
339 0 : const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
340 0 : basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon());
341 :
342 0 : if(aPolyPolygon.count())
343 : {
344 : // take care of wanted polygon type
345 0 : if(bToPoly)
346 : {
347 0 : if(aPolyPolygon.areControlPointsUsed())
348 : {
349 0 : aPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aPolyPolygon);
350 : }
351 : }
352 : else
353 : {
354 0 : if(!aPolyPolygon.areControlPointsUsed())
355 : {
356 0 : aPolyPolygon = basegfx::tools::expandToCurve(aPolyPolygon);
357 : }
358 : }
359 :
360 : // create ItemSet with object attributes
361 0 : SfxItemSet aAttributeSet(GetObjectItemSet());
362 0 : SdrPathObj* pPathObj = 0;
363 :
364 : // always clear objectshadow; this is included in the extraction
365 0 : aAttributeSet.Put(makeSdrShadowItem(false));
366 :
367 0 : if(rCandidate.getIsFilled())
368 : {
369 : // set needed items
370 0 : aAttributeSet.Put(XFillColorItem(OUString(), Color(rCandidate.getBColor())));
371 0 : aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
372 0 : aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
373 :
374 : // create filled SdrPathObj
375 0 : pPathObj = new SdrPathObj(OBJ_PATHFILL, aPolyPolygon);
376 : }
377 : else
378 : {
379 : // set needed items
380 0 : aAttributeSet.Put(XLineColorItem(OUString(), Color(rCandidate.getBColor())));
381 0 : aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
382 0 : aAttributeSet.Put(XLineWidthItem(0));
383 0 : aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
384 :
385 : // create line SdrPathObj
386 0 : pPathObj = new SdrPathObj(OBJ_PATHLINE, aPolyPolygon);
387 : }
388 :
389 : // copy basic information from original
390 0 : pPathObj->ImpSetAnchorPos(GetAnchorPos());
391 0 : pPathObj->NbcSetLayer(GetLayer());
392 :
393 0 : if(GetModel())
394 : {
395 0 : pPathObj->SetModel(GetModel());
396 0 : pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
397 : }
398 :
399 : // apply prepared ItemSet and add to target
400 0 : pPathObj->SetMergedItemSet(aAttributeSet);
401 0 : pObjectList->InsertObject(pPathObj);
402 : }
403 0 : }
404 :
405 : // postprocess; if no result and/or only one object, simplify
406 0 : if(!pObjectList->GetObjCount())
407 : {
408 0 : delete pGroup;
409 : }
410 0 : else if(1 == pObjectList->GetObjCount())
411 : {
412 0 : pRetval = pObjectList->RemoveObject(0);
413 0 : delete pGroup;
414 : }
415 : else
416 : {
417 0 : pRetval = pGroup;
418 : }
419 26 : }
420 : }
421 :
422 26 : return pRetval;
423 : }
424 :
425 :
426 :
427 0 : SdrObject* SdrTextObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
428 : {
429 0 : if(bAddText)
430 : {
431 0 : return ImpConvertContainedTextToSdrPathObjs(!bBezier);
432 : }
433 :
434 0 : return 0;
435 : }
436 :
437 56 : bool SdrTextObj::ImpCanConvTextToCurve() const
438 : {
439 56 : return !IsOutlText();
440 : }
441 :
442 26 : SdrObject* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier, bool bNoSetAttr) const
443 : {
444 26 : SdrObjKind ePathKind = bClosed ? OBJ_PATHFILL : OBJ_PATHLINE;
445 26 : basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
446 :
447 : // #i37011#
448 26 : if(!bBezier)
449 : {
450 6 : aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon);
451 6 : ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN;
452 : }
453 :
454 26 : SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon);
455 :
456 26 : if(bBezier)
457 : {
458 : // create bezier curves
459 20 : pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly()));
460 : }
461 :
462 26 : pPathObj->ImpSetAnchorPos(aAnchor);
463 26 : pPathObj->NbcSetLayer(SdrLayerID(GetLayer()));
464 :
465 26 : if(pModel)
466 : {
467 20 : pPathObj->SetModel(pModel);
468 :
469 20 : if(!bNoSetAttr)
470 : {
471 20 : sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
472 :
473 20 : pPathObj->ClearMergedItem();
474 20 : pPathObj->SetMergedItemSet(GetObjectItemSet());
475 20 : pPathObj->GetProperties().BroadcastItemChange(aC);
476 20 : pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
477 : }
478 : }
479 :
480 26 : return pPathObj;
481 : }
482 :
483 26 : SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, bool bBezier) const
484 : {
485 26 : if(!ImpCanConvTextToCurve())
486 : {
487 0 : return pObj;
488 : }
489 :
490 26 : SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
491 :
492 26 : if(!pText)
493 : {
494 26 : return pObj;
495 : }
496 :
497 0 : if(!pObj)
498 : {
499 0 : return pText;
500 : }
501 :
502 0 : if(pText->IsGroupObject())
503 : {
504 : // is already group object, add partial shape in front
505 0 : SdrObjList* pOL=pText->GetSubList();
506 0 : pOL->InsertObject(pObj,0);
507 :
508 0 : return pText;
509 : }
510 : else
511 : {
512 : // not yet a group, create one and add partial and new shapes
513 0 : SdrObjGroup* pGrp=new SdrObjGroup;
514 0 : SdrObjList* pOL=pGrp->GetSubList();
515 0 : pOL->InsertObject(pObj);
516 0 : pOL->InsertObject(pText);
517 :
518 0 : return pGrp;
519 : }
520 435 : }
521 :
522 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|