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 0 : void SdrTextObj::NbcSetSnapRect(const Rectangle& rRect)
43 : {
44 0 : if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) {
45 0 : Rectangle aSR0(GetSnapRect());
46 0 : long nWdt0=aSR0.Right()-aSR0.Left();
47 0 : long nHgt0=aSR0.Bottom()-aSR0.Top();
48 0 : long nWdt1=rRect.Right()-rRect.Left();
49 0 : long nHgt1=rRect.Bottom()-rRect.Top();
50 0 : SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
51 0 : SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
52 : } else {
53 0 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
54 0 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
55 0 : long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
56 0 : long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
57 0 : long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
58 0 : long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
59 0 : aRect=rRect;
60 0 : ImpJustifyRect(aRect);
61 :
62 : // #115391#
63 0 : AdaptTextMinSize();
64 :
65 0 : if (bTextFrame && (pModel==NULL || !pModel->IsPasteResize()))
66 : {
67 0 : NbcAdjustTextFrameWidthAndHeight();
68 : }
69 :
70 0 : ImpCheckShear();
71 0 : SetRectsDirty();
72 : }
73 0 : }
74 :
75 0 : const Rectangle& SdrTextObj::GetLogicRect() const
76 : {
77 0 : return aRect;
78 : }
79 :
80 0 : void SdrTextObj::NbcSetLogicRect(const Rectangle& rRect)
81 : {
82 0 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
83 0 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
84 0 : long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
85 0 : long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
86 0 : long nTWdt1=rRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
87 0 : long nTHgt1=rRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
88 0 : aRect=rRect;
89 0 : ImpJustifyRect(aRect);
90 :
91 : // #115391#
92 0 : AdaptTextMinSize();
93 :
94 0 : if(bTextFrame)
95 : {
96 0 : NbcAdjustTextFrameWidthAndHeight();
97 : }
98 :
99 0 : SetRectsDirty();
100 0 : }
101 :
102 0 : long SdrTextObj::GetRotateAngle() const
103 : {
104 0 : return aGeo.nDrehWink;
105 : }
106 :
107 0 : long SdrTextObj::GetShearAngle(bool /*bVertical*/) const
108 : {
109 0 : return aGeo.nShearWink;
110 : }
111 :
112 0 : void SdrTextObj::NbcMove(const Size& rSiz)
113 : {
114 0 : MoveRect(aRect,rSiz);
115 0 : MoveRect(aOutRect,rSiz);
116 0 : MoveRect(maSnapRect,rSiz);
117 0 : SetRectsDirty(true);
118 0 : }
119 :
120 0 : void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
121 : {
122 0 : bool bNoShearMerk=aGeo.nShearWink==0;
123 0 : bool bRota90Merk=bNoShearMerk && aGeo.nDrehWink % 9000 ==0;
124 0 : long nHDist=GetTextLeftDistance()+GetTextRightDistance();
125 0 : long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
126 0 : long nTWdt0=aRect.GetWidth ()-1-nHDist; if (nTWdt0<0) nTWdt0=0;
127 0 : long nTHgt0=aRect.GetHeight()-1-nVDist; if (nTHgt0<0) nTHgt0=0;
128 0 : bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
129 0 : bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
130 0 : if (bXMirr || bYMirr) {
131 0 : Point aRef1(GetSnapRect().Center());
132 0 : if (bXMirr) {
133 0 : Point aRef2(aRef1);
134 0 : aRef2.Y()++;
135 0 : NbcMirrorGluePoints(aRef1,aRef2);
136 : }
137 0 : if (bYMirr) {
138 0 : Point aRef2(aRef1);
139 0 : aRef2.X()++;
140 0 : NbcMirrorGluePoints(aRef1,aRef2);
141 : }
142 : }
143 :
144 0 : if (aGeo.nDrehWink==0 && aGeo.nShearWink==0) {
145 0 : ResizeRect(aRect,rRef,xFact,yFact);
146 0 : if (bYMirr) {
147 0 : aRect.Justify();
148 0 : aRect.Move(aRect.Right()-aRect.Left(),aRect.Bottom()-aRect.Top());
149 0 : aGeo.nDrehWink=18000;
150 0 : aGeo.RecalcSinCos();
151 : }
152 : }
153 : else
154 : {
155 0 : Polygon aPol(Rect2Poly(aRect,aGeo));
156 :
157 0 : for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
158 : {
159 0 : ResizePoint(aPol[a], rRef, xFact, yFact);
160 : }
161 :
162 0 : 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 0 : Poly2Rect(aPol, aRect, aGeo);
175 : }
176 :
177 0 : if (bRota90Merk) {
178 0 : bool bRota90=aGeo.nDrehWink % 9000 ==0;
179 0 : 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 0 : if (bNoShearMerk!=(aGeo.nShearWink==0)) { // correct a rounding error occurring with Shear
190 0 : aGeo.nShearWink=0;
191 0 : aGeo.RecalcTan();
192 : }
193 : }
194 :
195 0 : ImpJustifyRect(aRect);
196 :
197 0 : long nTWdt1=aRect.GetWidth ()-1-nHDist; if (nTWdt1<0) nTWdt1=0;
198 0 : long nTHgt1=aRect.GetHeight()-1-nVDist; if (nTHgt1<0) nTHgt1=0;
199 :
200 : // #115391#
201 0 : AdaptTextMinSize();
202 :
203 0 : if(bTextFrame && (!pModel || !pModel->IsPasteResize()))
204 : {
205 0 : NbcAdjustTextFrameWidthAndHeight();
206 : }
207 :
208 0 : ImpCheckShear();
209 0 : SetRectsDirty();
210 0 : }
211 :
212 0 : void SdrTextObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
213 : {
214 0 : SetGlueReallyAbsolute(true);
215 0 : long dx=aRect.Right()-aRect.Left();
216 0 : long dy=aRect.Bottom()-aRect.Top();
217 0 : Point aP(aRect.TopLeft());
218 0 : RotatePoint(aP,rRef,sn,cs);
219 0 : aRect.Left()=aP.X();
220 0 : aRect.Top()=aP.Y();
221 0 : aRect.Right()=aRect.Left()+dx;
222 0 : aRect.Bottom()=aRect.Top()+dy;
223 0 : if (aGeo.nDrehWink==0) {
224 0 : aGeo.nDrehWink=NormAngle360(nWink);
225 0 : aGeo.nSin=sn;
226 0 : aGeo.nCos=cs;
227 : } else {
228 0 : aGeo.nDrehWink=NormAngle360(aGeo.nDrehWink+nWink);
229 0 : aGeo.RecalcSinCos();
230 : }
231 0 : SetRectsDirty();
232 0 : NbcRotateGluePoints(rRef,nWink,sn,cs);
233 0 : SetGlueReallyAbsolute(false);
234 0 : }
235 :
236 0 : void SdrTextObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
237 : {
238 0 : SetGlueReallyAbsolute(true);
239 :
240 : // when this is a SdrPathObj, aRect may be uninitialized
241 0 : Polygon aPol(Rect2Poly(aRect.IsEmpty() ? GetSnapRect() : aRect, aGeo));
242 :
243 0 : sal_uInt16 nPointCount=aPol.GetSize();
244 0 : for (sal_uInt16 i=0; i<nPointCount; i++) {
245 0 : ShearPoint(aPol[i],rRef,tn,bVShear);
246 : }
247 0 : Poly2Rect(aPol,aRect,aGeo);
248 0 : ImpJustifyRect(aRect);
249 0 : if (bTextFrame) {
250 0 : NbcAdjustTextFrameWidthAndHeight();
251 : }
252 0 : ImpCheckShear();
253 0 : SetRectsDirty();
254 0 : NbcShearGluePoints(rRef,nWink,tn,bVShear);
255 0 : SetGlueReallyAbsolute(false);
256 0 : }
257 :
258 0 : void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
259 : {
260 0 : SetGlueReallyAbsolute(true);
261 0 : bool bNoShearMerk=aGeo.nShearWink==0;
262 0 : bool bRota90Merk = false;
263 0 : if (bNoShearMerk &&
264 0 : (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
265 0 : std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
266 0 : bRota90Merk=aGeo.nDrehWink % 9000 ==0;
267 : }
268 0 : Polygon aPol(Rect2Poly(aRect,aGeo));
269 : sal_uInt16 i;
270 0 : sal_uInt16 nPntAnz=aPol.GetSize();
271 0 : for (i=0; i<nPntAnz; i++) {
272 0 : MirrorPoint(aPol[i],rRef1,rRef2);
273 : }
274 : // turn polygon and move it a little
275 0 : Polygon aPol0(aPol);
276 0 : aPol[0]=aPol0[1];
277 0 : aPol[1]=aPol0[0];
278 0 : aPol[2]=aPol0[3];
279 0 : aPol[3]=aPol0[2];
280 0 : aPol[4]=aPol0[1];
281 0 : Poly2Rect(aPol,aRect,aGeo);
282 :
283 0 : if (bRota90Merk) {
284 0 : bool bRota90=aGeo.nDrehWink % 9000 ==0;
285 0 : 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 0 : if (bNoShearMerk!=(aGeo.nShearWink==0)) { // correct a rounding error occurring with Shear
297 0 : aGeo.nShearWink=0;
298 0 : aGeo.RecalcTan();
299 : }
300 :
301 0 : ImpJustifyRect(aRect);
302 0 : if (bTextFrame) {
303 0 : NbcAdjustTextFrameWidthAndHeight();
304 : }
305 0 : ImpCheckShear();
306 0 : SetRectsDirty();
307 0 : NbcMirrorGluePoints(rRef1,rRef2);
308 0 : SetGlueReallyAbsolute(false);
309 0 : }
310 :
311 :
312 :
313 0 : SdrObject* SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
314 : {
315 0 : SdrObject* pRetval = 0;
316 :
317 0 : if(!ImpCanConvTextToCurve())
318 : {
319 : // suppress HelpTexts from PresObj's
320 0 : return 0;
321 : }
322 :
323 : // get primitives
324 0 : const drawinglayer::primitive2d::Primitive2DSequence xSequence(GetViewContact().getViewIndependentPrimitive2DSequence());
325 :
326 0 : if(xSequence.hasElements())
327 : {
328 : // create an extractor with neutral ViewInformation
329 0 : const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
330 0 : drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
331 :
332 : // extract text as polygons
333 0 : aExtractor.process(xSequence);
334 :
335 : // get results
336 0 : const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
337 0 : const sal_uInt32 nResultCount(rResult.size());
338 :
339 0 : 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 0 : }
429 : }
430 :
431 0 : 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 0 : bool SdrTextObj::ImpCanConvTextToCurve() const
447 : {
448 0 : return !IsOutlText();
449 : }
450 :
451 0 : SdrObject* SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier, bool bNoSetAttr) const
452 : {
453 0 : SdrObjKind ePathKind = bClosed ? OBJ_PATHFILL : OBJ_PATHLINE;
454 0 : basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
455 :
456 : // #i37011#
457 0 : if(!bBezier)
458 : {
459 0 : aB2DPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(aB2DPolyPolygon);
460 0 : ePathKind = bClosed ? OBJ_POLY : OBJ_PLIN;
461 : }
462 :
463 0 : SdrPathObj* pPathObj = new SdrPathObj(ePathKind, aB2DPolyPolygon);
464 :
465 0 : if(bBezier)
466 : {
467 : // create bezier curves
468 0 : pPathObj->SetPathPoly(basegfx::tools::expandToCurve(pPathObj->GetPathPoly()));
469 : }
470 :
471 0 : if(pPathObj)
472 : {
473 0 : pPathObj->ImpSetAnchorPos(aAnchor);
474 0 : pPathObj->NbcSetLayer(SdrLayerID(GetLayer()));
475 :
476 0 : if(pModel)
477 : {
478 0 : pPathObj->SetModel(pModel);
479 :
480 0 : if(!bNoSetAttr)
481 : {
482 0 : sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
483 :
484 0 : pPathObj->ClearMergedItem();
485 0 : pPathObj->SetMergedItemSet(GetObjectItemSet());
486 0 : pPathObj->GetProperties().BroadcastItemChange(aC);
487 0 : pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
488 : }
489 : }
490 : }
491 :
492 0 : return pPathObj;
493 : }
494 :
495 0 : SdrObject* SdrTextObj::ImpConvertAddText(SdrObject* pObj, bool bBezier) const
496 : {
497 0 : if(!ImpCanConvTextToCurve())
498 : {
499 0 : return pObj;
500 : }
501 :
502 0 : SdrObject* pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
503 :
504 0 : if(!pText)
505 : {
506 0 : 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: */
|