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 45056 : void SdrTextObj::NbcSetSnapRect(const Rectangle& rRect)
44 : {
45 45056 : if (aGeo.nRotationAngle!=0 || aGeo.nShearAngle!=0)
46 : {
47 : // Either the rotation or shear angle exists.
48 16 : Rectangle aSR0(GetSnapRect());
49 16 : long nWdt0=aSR0.Right()-aSR0.Left();
50 16 : long nHgt0=aSR0.Bottom()-aSR0.Top();
51 16 : long nWdt1=rRect.Right()-rRect.Left();
52 16 : long nHgt1=rRect.Bottom()-rRect.Top();
53 16 : SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
54 16 : SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
55 : }
56 : else
57 : {
58 : // No rotation or shear.
59 :
60 45040 : aRect=rRect;
61 45040 : ImpJustifyRect(aRect);
62 :
63 : // #115391#
64 45040 : AdaptTextMinSize();
65 :
66 45040 : ImpCheckShear();
67 45040 : SetRectsDirty();
68 : }
69 45056 : }
70 :
71 270807 : const Rectangle& SdrTextObj::GetLogicRect() const
72 : {
73 270807 : return aRect;
74 : }
75 :
76 48524 : void SdrTextObj::NbcSetLogicRect(const Rectangle& rRect)
77 : {
78 48524 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
79 48524 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
80 48524 : long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
81 48524 : long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
82 48524 : long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
83 48524 : long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
84 48524 : aRect=rRect;
85 48524 : ImpJustifyRect(aRect);
86 :
87 : // #115391#
88 48524 : AdaptTextMinSize();
89 :
90 48524 : SetRectsDirty();
91 48524 : }
92 :
93 10448 : long SdrTextObj::GetRotateAngle() const
94 : {
95 10448 : return aGeo.nRotationAngle;
96 : }
97 :
98 0 : long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
99 : {
100 0 : return aGeo.nShearAngle;
101 : }
102 :
103 99093 : void SdrTextObj::NbcMove(const Size& rSiz)
104 : {
105 99093 : MoveRect(aRect,rSiz);
106 99093 : MoveRect(aOutRect,rSiz);
107 99093 : MoveRect(maSnapRect,rSiz);
108 99093 : SetRectsDirty(true);
109 99093 : }
110 :
111 27150 : void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
112 : {
113 27150 : bool bNoShearMerk=aGeo.nShearAngle==0;
114 27150 : bool bRota90Merk=bNoShearMerk && aGeo.nRotationAngle % 9000 ==0;
115 27150 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
116 27150 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
117 27150 : long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
118 27150 : long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
119 27150 : bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
120 27150 : bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
121 27150 : if (bXMirr || bYMirr) {
122 23718 : Point aRef1(GetSnapRect().Center());
123 23718 : if (bXMirr) {
124 23718 : Point aRef2(aRef1);
125 23718 : aRef2.Y()++;
126 23718 : NbcMirrorGluePoints(aRef1,aRef2);
127 : }
128 23718 : if (bYMirr) {
129 23718 : Point aRef2(aRef1);
130 23718 : aRef2.X()++;
131 23718 : NbcMirrorGluePoints(aRef1,aRef2);
132 : }
133 : }
134 :
135 27150 : if (aGeo.nRotationAngle==0 && aGeo.nShearAngle==0) {
136 14165 : ResizeRect(aRect,rRef,xFact,yFact);
137 28330 : if (bYMirr) {
138 12203 : aRect.Justify();
139 12203 : aRect.Move(aRect.Right()-aRect.Left(),aRect.Bottom()-aRect.Top());
140 12203 : aGeo.nRotationAngle=18000;
141 12203 : aGeo.RecalcSinCos();
142 : }
143 : }
144 : else
145 : {
146 12985 : Polygon aPol(Rect2Poly(aRect,aGeo));
147 :
148 77910 : for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
149 : {
150 64925 : ResizePoint(aPol[a], rRef, xFact, yFact);
151 : }
152 :
153 12985 : 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 12985 : Poly2Rect(aPol, aRect, aGeo);
166 : }
167 :
168 27150 : if (bRota90Merk) {
169 26404 : bool bRota90=aGeo.nRotationAngle % 9000 ==0;
170 26404 : 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 26404 : if (bNoShearMerk!=(aGeo.nShearAngle==0)) { // correct a rounding error occurring with Shear
181 11525 : aGeo.nShearAngle=0;
182 11525 : aGeo.RecalcTan();
183 : }
184 : }
185 :
186 27150 : ImpJustifyRect(aRect);
187 :
188 27150 : long nTWdt1=aRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
189 27150 : long nTHgt1=aRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
190 :
191 : // #115391#
192 27150 : AdaptTextMinSize();
193 :
194 27150 : if(bTextFrame && (!pModel || !pModel->IsPasteResize()))
195 : {
196 282 : NbcAdjustTextFrameWidthAndHeight();
197 : }
198 :
199 27150 : ImpCheckShear();
200 27150 : SetRectsDirty();
201 27150 : }
202 :
203 1541 : void SdrTextObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
204 : {
205 1541 : SetGlueReallyAbsolute(true);
206 1541 : long dx=aRect.Right()-aRect.Left();
207 1541 : long dy=aRect.Bottom()-aRect.Top();
208 1541 : Point aP(aRect.TopLeft());
209 1541 : RotatePoint(aP,rRef,sn,cs);
210 1541 : aRect.Left()=aP.X();
211 1541 : aRect.Top()=aP.Y();
212 1541 : aRect.Right()=aRect.Left()+dx;
213 1541 : aRect.Bottom()=aRect.Top()+dy;
214 1541 : if (aGeo.nRotationAngle==0) {
215 1405 : aGeo.nRotationAngle=NormAngle360(nWink);
216 1405 : aGeo.nSin=sn;
217 1405 : aGeo.nCos=cs;
218 : } else {
219 136 : aGeo.nRotationAngle=NormAngle360(aGeo.nRotationAngle+nWink);
220 136 : aGeo.RecalcSinCos();
221 : }
222 1541 : SetRectsDirty();
223 1541 : NbcRotateGluePoints(rRef,nWink,sn,cs);
224 1541 : SetGlueReallyAbsolute(false);
225 1541 : }
226 :
227 4 : void SdrTextObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
228 : {
229 4 : SetGlueReallyAbsolute(true);
230 :
231 : // when this is a SdrPathObj, aRect may be uninitialized
232 4 : Polygon aPol(Rect2Poly(aRect.IsEmpty() ? GetSnapRect() : aRect, aGeo));
233 :
234 4 : sal_uInt16 nPointCount=aPol.GetSize();
235 24 : for (sal_uInt16 i=0; i<nPointCount; i++) {
236 20 : ShearPoint(aPol[i],rRef,tn,bVShear);
237 : }
238 4 : Poly2Rect(aPol,aRect,aGeo);
239 4 : ImpJustifyRect(aRect);
240 4 : if (bTextFrame) {
241 0 : NbcAdjustTextFrameWidthAndHeight();
242 : }
243 4 : ImpCheckShear();
244 4 : SetRectsDirty();
245 4 : NbcShearGluePoints(rRef,nWink,tn,bVShear);
246 4 : SetGlueReallyAbsolute(false);
247 4 : }
248 :
249 812 : void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
250 : {
251 812 : SetGlueReallyAbsolute(true);
252 812 : bool bNoShearMerk=aGeo.nShearAngle==0;
253 812 : bool bRota90Merk = false;
254 2436 : if (bNoShearMerk &&
255 1488 : (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
256 0 : std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
257 812 : bRota90Merk=aGeo.nRotationAngle % 9000 ==0;
258 : }
259 812 : Polygon aPol(Rect2Poly(aRect,aGeo));
260 : sal_uInt16 i;
261 812 : sal_uInt16 nPntAnz=aPol.GetSize();
262 4872 : for (i=0; i<nPntAnz; i++) {
263 4060 : MirrorPoint(aPol[i],rRef1,rRef2);
264 : }
265 : // turn polygon and move it a little
266 1624 : Polygon aPol0(aPol);
267 812 : aPol[0]=aPol0[1];
268 812 : aPol[1]=aPol0[0];
269 812 : aPol[2]=aPol0[3];
270 812 : aPol[3]=aPol0[2];
271 812 : aPol[4]=aPol0[1];
272 812 : Poly2Rect(aPol,aRect,aGeo);
273 :
274 812 : if (bRota90Merk) {
275 766 : bool bRota90=aGeo.nRotationAngle % 9000 ==0;
276 766 : 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 812 : if (bNoShearMerk!=(aGeo.nShearAngle==0)) { // correct a rounding error occurring with Shear
288 38 : aGeo.nShearAngle=0;
289 38 : aGeo.RecalcTan();
290 : }
291 :
292 812 : ImpJustifyRect(aRect);
293 812 : if (bTextFrame) {
294 20 : NbcAdjustTextFrameWidthAndHeight();
295 : }
296 812 : ImpCheckShear();
297 812 : SetRectsDirty();
298 812 : NbcMirrorGluePoints(rRef1,rRef2);
299 1624 : SetGlueReallyAbsolute(false);
300 812 : }
301 :
302 :
303 :
304 52 : SdrObject* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
305 : {
306 52 : SdrObject* pRetval = 0;
307 :
308 52 : if(!ImpCanConvTextToCurve())
309 : {
310 : // suppress HelpTexts from PresObj's
311 0 : return 0;
312 : }
313 :
314 : // get primitives
315 52 : const drawinglayer::primitive2d::Primitive2DSequence xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
316 :
317 52 : if(xSequence.hasElements())
318 : {
319 : // create an extractor with neutral ViewInformation
320 52 : const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
321 104 : drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
322 :
323 : // extract text as polygons
324 52 : aExtractor.process(xSequence);
325 :
326 : // get results
327 52 : const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
328 52 : const sal_uInt32 nResultCount(rResult.size());
329 :
330 52 : 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(XLINE_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(XLINE_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 52 : }
420 : }
421 :
422 52 : 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 104 : bool SdrTextObj::ImpCanConvTextToCurve() const
438 : {
439 104 : return !IsOutlText();
440 : }
441 :
442 52 : SdrObject* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier, bool bNoSetAttr) const
443 : {
444 52 : SdrObjKind ePathKind = bClosed ? OBJ_PATHFILL : OBJ_PATHLINE;
445 52 : basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
446 :
447 : // #i37011#
448 52 : if(!bBezier)
449 : {
450 12 : aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon);
451 12 : ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN;
452 : }
453 :
454 52 : SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon);
455 :
456 52 : if(bBezier)
457 : {
458 : // create bezier curves
459 40 : pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly()));
460 : }
461 :
462 52 : if(pPathObj)
463 : {
464 52 : pPathObj->ImpSetAnchorPos(aAnchor);
465 52 : pPathObj->NbcSetLayer(SdrLayerID(GetLayer()));
466 :
467 52 : if(pModel)
468 : {
469 40 : pPathObj->SetModel(pModel);
470 :
471 40 : if(!bNoSetAttr)
472 : {
473 40 : sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
474 :
475 40 : pPathObj->ClearMergedItem();
476 40 : pPathObj->SetMergedItemSet(GetObjectItemSet());
477 40 : pPathObj->GetProperties().BroadcastItemChange(aC);
478 40 : pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
479 : }
480 : }
481 : }
482 :
483 52 : return pPathObj;
484 : }
485 :
486 52 : SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, bool bBezier) const
487 : {
488 52 : if(!ImpCanConvTextToCurve())
489 : {
490 0 : return pObj;
491 : }
492 :
493 52 : SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
494 :
495 52 : if(!pText)
496 : {
497 52 : return pObj;
498 : }
499 :
500 0 : if(!pObj)
501 : {
502 0 : return pText;
503 : }
504 :
505 0 : if(pText->IsGroupObject())
506 : {
507 : // is already group object, add partial shape in front
508 0 : SdrObjList* pOL=pText->GetSubList();
509 0 : pOL->InsertObject(pObj,0);
510 :
511 0 : return pText;
512 : }
513 : else
514 : {
515 : // not yet a group, create one and add partial and new shapes
516 0 : SdrObjGroup* pGrp=new SdrObjGroup;
517 0 : SdrObjList* pOL=pGrp->GetSubList();
518 0 : pOL->InsertObject(pObj);
519 0 : pOL->InsertObject(pText);
520 :
521 0 : return pGrp;
522 : }
523 651 : }
524 :
525 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|