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