LibreOffice Module svx (master)  1
svdotxtr.cxx
Go to the documentation of this file.
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/svdpage.hxx>
26 #include <svx/svdmodel.hxx>
30 #include <svl/itemset.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xflclit.hxx>
35 #include <svx/xlineit0.hxx>
36 #include <svx/xlnclit.hxx>
37 #include <svx/xlnwtit.hxx>
38 #include <svx/sdshitm.hxx>
39 
40 using namespace com::sun::star;
41 
43 {
44  if (maGeo.nRotationAngle || maGeo.nShearAngle)
45  {
46  // Either the rotation or shear angle exists.
47  tools::Rectangle aSR0(GetSnapRect());
48  tools::Long nWdt0=aSR0.Right()-aSR0.Left();
49  tools::Long nHgt0=aSR0.Bottom()-aSR0.Top();
50  tools::Long nWdt1=rRect.Right()-rRect.Left();
51  tools::Long nHgt1=rRect.Bottom()-rRect.Top();
52  SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
53  SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
54  }
55  else
56  {
57  // No rotation or shear.
58 
59  maRect = rRect;
60  ImpJustifyRect(maRect);
61 
62  AdaptTextMinSize();
63 
64  ImpCheckShear();
65  SetBoundAndSnapRectsDirty();
66  }
67 }
68 
70 {
71  return maRect;
72 }
73 
75 {
76  maRect = rRect;
77  ImpJustifyRect(maRect);
78 
79  AdaptTextMinSize();
80 
81  SetBoundAndSnapRectsDirty();
82 }
83 
85 {
86  return maGeo.nRotationAngle;
87 }
88 
89 Degree100 SdrTextObj::GetShearAngle(bool /*bVertical*/) const
90 {
91  return maGeo.nShearAngle;
92 }
93 
94 void SdrTextObj::NbcMove(const Size& rSiz)
95 {
96  maRect.Move(rSiz);
97  m_aOutRect.Move(rSiz);
98  maSnapRect.Move(rSiz);
99  SetBoundAndSnapRectsDirty(true);
100 }
101 
102 void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
103 {
104  bool bNotSheared=maGeo.nShearAngle==0_deg100;
105  bool bRotate90=bNotSheared && maGeo.nRotationAngle.get() % 9000 ==0;
106  bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
107  bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
108  if (bXMirr || bYMirr) {
109  Point aRef1(GetSnapRect().Center());
110  if (bXMirr) {
111  Point aRef2(aRef1);
112  aRef2.AdjustY( 1 );
113  NbcMirrorGluePoints(aRef1,aRef2);
114  }
115  if (bYMirr) {
116  Point aRef2(aRef1);
117  aRef2.AdjustX( 1 );
118  NbcMirrorGluePoints(aRef1,aRef2);
119  }
120  }
121 
122  if (maGeo.nRotationAngle==0_deg100 && maGeo.nShearAngle==0_deg100) {
123  ResizeRect(maRect,rRef,xFact,yFact);
124  if (bYMirr) {
125  maRect.Justify();
126  maRect.Move(maRect.Right()-maRect.Left(),maRect.Bottom()-maRect.Top());
127  maGeo.nRotationAngle=18000_deg100;
128  maGeo.RecalcSinCos();
129  }
130  }
131  else
132  {
133  tools::Polygon aPol(Rect2Poly(maRect,maGeo));
134 
135  for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
136  {
137  ResizePoint(aPol[a], rRef, xFact, yFact);
138  }
139 
140  if(bXMirr != bYMirr)
141  {
142  // turn polygon and move it a little
143  tools::Polygon aPol0(aPol);
144 
145  aPol[0] = aPol0[1];
146  aPol[1] = aPol0[0];
147  aPol[2] = aPol0[3];
148  aPol[3] = aPol0[2];
149  aPol[4] = aPol0[1];
150  }
151 
152  Poly2Rect(aPol, maRect, maGeo);
153  }
154 
155  if (bRotate90) {
156  bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
157  if (!bRota90) { // there's seems to be a rounding error occurring: correct it
158  Degree100 a=NormAngle36000(maGeo.nRotationAngle);
159  if (a<4500_deg100) a=0_deg100;
160  else if (a<13500_deg100) a=9000_deg100;
161  else if (a<22500_deg100) a=18000_deg100;
162  else if (a<31500_deg100) a=27000_deg100;
163  else a=0_deg100;
164  maGeo.nRotationAngle=a;
165  maGeo.RecalcSinCos();
166  }
167  if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
168  maGeo.nShearAngle=0_deg100;
169  maGeo.RecalcTan();
170  }
171  }
172 
173  ImpJustifyRect(maRect);
174 
175  AdaptTextMinSize();
176 
177  if(mbTextFrame && !getSdrModelFromSdrObject().IsPasteResize())
178  {
179  NbcAdjustTextFrameWidthAndHeight();
180  }
181 
182  ImpCheckShear();
183  SetBoundAndSnapRectsDirty();
184 }
185 
186 void SdrTextObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
187 {
188  SetGlueReallyAbsolute(true);
189  tools::Long dx=maRect.Right()-maRect.Left();
190  tools::Long dy=maRect.Bottom()-maRect.Top();
191  Point aP(maRect.TopLeft());
192  RotatePoint(aP,rRef,sn,cs);
193  maRect.SetLeft(aP.X() );
194  maRect.SetTop(aP.Y() );
195  maRect.SetRight(maRect.Left()+dx );
196  maRect.SetBottom(maRect.Top()+dy );
197  if (maGeo.nRotationAngle==0_deg100) {
198  maGeo.nRotationAngle=NormAngle36000(nAngle);
199  maGeo.mfSinRotationAngle=sn;
200  maGeo.mfCosRotationAngle=cs;
201  } else {
202  maGeo.nRotationAngle=NormAngle36000(maGeo.nRotationAngle+nAngle);
203  maGeo.RecalcSinCos();
204  }
205  SetBoundAndSnapRectsDirty();
206  NbcRotateGluePoints(rRef,nAngle,sn,cs);
207  SetGlueReallyAbsolute(false);
208 }
209 
210 void SdrTextObj::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
211 {
212  SetGlueReallyAbsolute(true);
213 
214  // when this is a SdrPathObj, aRect may be uninitialized
215  tools::Polygon aPol(Rect2Poly(maRect.IsEmpty() ? GetSnapRect() : maRect, maGeo));
216 
217  sal_uInt16 nPointCount=aPol.GetSize();
218  for (sal_uInt16 i=0; i<nPointCount; i++) {
219  ShearPoint(aPol[i],rRef,tn,bVShear);
220  }
221  Poly2Rect(aPol,maRect,maGeo);
222  ImpJustifyRect(maRect);
223  if (mbTextFrame) {
224  NbcAdjustTextFrameWidthAndHeight();
225  }
226  ImpCheckShear();
227  SetBoundAndSnapRectsDirty();
228  NbcShearGluePoints(rRef,tn,bVShear);
229  SetGlueReallyAbsolute(false);
230 }
231 
232 void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
233 {
234  SetGlueReallyAbsolute(true);
235  bool bNotSheared=maGeo.nShearAngle==0_deg100;
236  bool bRotate90 = false;
237  if (bNotSheared &&
238  (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
239  std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
240  bRotate90=maGeo.nRotationAngle.get() % 9000 ==0;
241  }
242  tools::Polygon aPol(Rect2Poly(maRect,maGeo));
243  sal_uInt16 i;
244  sal_uInt16 nPointCount=aPol.GetSize();
245  for (i=0; i<nPointCount; i++) {
246  MirrorPoint(aPol[i],rRef1,rRef2);
247  }
248  // turn polygon and move it a little
249  tools::Polygon aPol0(aPol);
250  aPol[0]=aPol0[1];
251  aPol[1]=aPol0[0];
252  aPol[2]=aPol0[3];
253  aPol[3]=aPol0[2];
254  aPol[4]=aPol0[1];
255  Poly2Rect(aPol,maRect,maGeo);
256 
257  if (bRotate90) {
258  bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
259  if (bRotate90 && !bRota90) { // there's seems to be a rounding error occurring: correct it
260  Degree100 a=NormAngle36000(maGeo.nRotationAngle);
261  if (a<4500_deg100) a=0_deg100;
262  else if (a<13500_deg100) a=9000_deg100;
263  else if (a<22500_deg100) a=18000_deg100;
264  else if (a<31500_deg100) a=27000_deg100;
265  else a=0_deg100;
266  maGeo.nRotationAngle=a;
267  maGeo.RecalcSinCos();
268  }
269  }
270  if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
271  maGeo.nShearAngle=0_deg100;
272  maGeo.RecalcTan();
273  }
274 
275  ImpJustifyRect(maRect);
276  if (mbTextFrame) {
277  NbcAdjustTextFrameWidthAndHeight();
278  }
279  ImpCheckShear();
280  SetBoundAndSnapRectsDirty();
281  NbcMirrorGluePoints(rRef1,rRef2);
282  SetGlueReallyAbsolute(false);
283 }
284 
285 
287 {
288  SdrObjectUniquePtr pRetval;
289 
290  if(!ImpCanConvTextToCurve())
291  {
292  // suppress HelpTexts from PresObj's
293  return nullptr;
294  }
295 
296  // create an extractor with neutral ViewInformation
297  const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
298  drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
299 
300  // extract text as polygons
301  GetViewContact().getViewIndependentPrimitive2DContainer(aExtractor);
302 
303  // get results
305  const sal_uInt32 nResultCount(rResult.size());
306 
307  if(nResultCount)
308  {
309  // prepare own target
310  SdrObjGroup* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
311  SdrObjList* pObjectList = pGroup->GetSubList();
312 
313  // process results
314  for(sal_uInt32 a(0); a < nResultCount; a++)
315  {
316  const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
317  basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon());
318 
319  if(aPolyPolygon.count())
320  {
321  // take care of wanted polygon type
322  if(bToPoly)
323  {
324  if(aPolyPolygon.areControlPointsUsed())
325  {
326  aPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon);
327  }
328  }
329  else
330  {
331  if(!aPolyPolygon.areControlPointsUsed())
332  {
333  aPolyPolygon = basegfx::utils::expandToCurve(aPolyPolygon);
334  }
335  }
336 
337  // create ItemSet with object attributes
338  SfxItemSet aAttributeSet(GetObjectItemSet());
339  SdrPathObj* pPathObj = nullptr;
340 
341  // always clear objectshadow; this is included in the extraction
342  aAttributeSet.Put(makeSdrShadowItem(false));
343 
344  if(rCandidate.getIsFilled())
345  {
346  // set needed items
347  aAttributeSet.Put(XFillColorItem(OUString(), Color(rCandidate.getBColor())));
348  aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
349  aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
350 
351  // create filled SdrPathObj
352  pPathObj = new SdrPathObj(
353  getSdrModelFromSdrObject(),
355  aPolyPolygon);
356  }
357  else
358  {
359  // set needed items
360  aAttributeSet.Put(XLineColorItem(OUString(), Color(rCandidate.getBColor())));
361  aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
362  aAttributeSet.Put(XLineWidthItem(0));
363  aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
364 
365  // create line SdrPathObj
366  pPathObj = new SdrPathObj(
367  getSdrModelFromSdrObject(),
369  aPolyPolygon);
370  }
371 
372  // copy basic information from original
373  pPathObj->ImpSetAnchorPos(GetAnchorPos());
374  pPathObj->NbcSetLayer(GetLayer());
375  pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
376 
377  // apply prepared ItemSet and add to target
378  pPathObj->SetMergedItemSet(aAttributeSet);
379  pObjectList->InsertObject(pPathObj);
380  }
381  }
382 
383  // postprocess; if no result and/or only one object, simplify
384  if(!pObjectList->GetObjCount())
385  {
386  // always use SdrObject::Free(...) for SdrObjects (!)
387  SdrObject* pTemp(pGroup);
388  SdrObject::Free(pTemp);
389  }
390  else if(1 == pObjectList->GetObjCount())
391  {
392  pRetval.reset(pObjectList->RemoveObject(0));
393 
394  // always use SdrObject::Free(...) for SdrObjects (!)
395  SdrObject* pTemp(pGroup);
396  SdrObject::Free(pTemp);
397  }
398  else
399  {
400  pRetval.reset(pGroup);
401  }
402  }
403 
404  return pRetval;
405 }
406 
407 
408 SdrObjectUniquePtr SdrTextObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
409 {
410  if(bAddText)
411  {
412  return ImpConvertContainedTextToSdrPathObjs(!bBezier);
413  }
414 
415  return nullptr;
416 }
417 
419 {
420  return !IsOutlText();
421 }
422 
423 SdrPathObjUniquePtr SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier) const
424 {
425  SdrObjKind ePathKind = bClosed ? SdrObjKind::PathFill : SdrObjKind::PathLine;
426  basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
427 
428  // #i37011#
429  if(!bBezier)
430  {
431  aB2DPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aB2DPolyPolygon);
432  ePathKind = bClosed ? SdrObjKind::Polygon : SdrObjKind::PolyLine;
433  }
434 
435  SdrPathObjUniquePtr pPathObj(new SdrPathObj(
436  getSdrModelFromSdrObject(),
437  ePathKind,
438  aB2DPolyPolygon));
439 
440  if(bBezier)
441  {
442  // create bezier curves
443  pPathObj->SetPathPoly(basegfx::utils::expandToCurve(pPathObj->GetPathPoly()));
444  }
445 
446  pPathObj->ImpSetAnchorPos(m_aAnchor);
447  pPathObj->NbcSetLayer(GetLayer());
449  pPathObj->ClearMergedItem();
450  pPathObj->SetMergedItemSet(GetObjectItemSet());
451  pPathObj->GetProperties().BroadcastItemChange(aC);
452  pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
453 
454  return pPathObj;
455 }
456 
458 {
459  if(!ImpCanConvTextToCurve())
460  {
461  return pObj;
462  }
463 
464  SdrObjectUniquePtr pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
465 
466  if(!pText)
467  {
468  return pObj;
469  }
470 
471  if(!pObj)
472  {
473  return pText;
474  }
475 
476  if(pText->IsGroupObject())
477  {
478  // is already group object, add partial shape in front
479  SdrObjList* pOL=pText->GetSubList();
480  pOL->InsertObject(pObj.release(),0);
481 
482  return pText;
483  }
484  else
485  {
486  // not yet a group, create one and add partial and new shapes
487  std::unique_ptr<SdrObjGroup, SdrObjectFreeOp> pGrp(new SdrObjGroup(getSdrModelFromSdrObject()));
488  SdrObjList* pOL=pGrp->GetSubList();
489  pOL->InsertObject(pObj.release());
490  pOL->InsertObject(pText.release());
491 
492  return pGrp;
493  }
494 }
495 
496 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::vector< TextAsPolygonDataNode > TextAsPolygonDataNodeVector
virtual void NbcResize(const Point &rRef, const Fraction &xFact, const Fraction &yFact) override
Definition: svdotxtr.cxx:102
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:109
void ResizePoint(Point &rPnt, const Point &rRef, const Fraction &xFract, const Fraction &yFract)
Definition: svdtrans.hxx:93
constexpr tools::Long Left() const
const TextAsPolygonDataNodeVector & getTarget() const
void Poly2Rect(const tools::Polygon &rPol, tools::Rectangle &rRect, GeoStat &rGeo)
Definition: svdtrans.cxx:480
B2DPolygon expandToCurve(const B2DPolygon &rCandidate)
long Long
bool ImpCanConvTextToCurve() const
Definition: svdotxtr.cxx:418
const basegfx::B2DPolyPolygon & getB2DPolyPolygon() const
size_t GetObjCount() const
Definition: svdpage.cxx:801
SdrObjectUniquePtr ImpConvertAddText(SdrObjectUniquePtr pObj, bool bBezier) const
Definition: svdotxtr.cxx:457
open Bezier-curve
static void Free(SdrObject *&_rpObject)
Definition: svdobj.cxx:471
virtual void InsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
Definition: svdpage.cxx:329
Center
std::unique_ptr< SdrPathObj, SdrObjectFreeOp > SdrPathObjUniquePtr
Definition: svdotext.hxx:123
void ImpSetAnchorPos(const Point &rPnt)
Definition: svdobj.cxx:1628
virtual void NbcMirror(const Point &rRef1, const Point &rRef2) override
Definition: svdotxtr.cxx:232
SdrObjKind
Definition: svdobjkind.hxx:24
SVX_DLLPRIVATE SdrObjectUniquePtr ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
Definition: svdotxtr.cxx:286
void SetMergedItemSet(const SfxItemSet &rSet, bool bClearAllItems=false)
Definition: svdobj.cxx:1997
virtual void NbcShear(const Point &rRef, Degree100 nAngle, double tn, bool bVShear) override
Definition: svdotxtr.cxx:210
void ResizeRect(tools::Rectangle &rRect, const Point &rRef, const Fraction &rxFact, const Fraction &ryFact)
Definition: svdtrans.cxx:38
int i
uno_Any a
SdrPathObjUniquePtr ImpConvertMakeObj(const basegfx::B2DPolyPolygon &rPolyPolygon, bool bClosed, bool bBezier) const
Definition: svdotxtr.cxx:423
const basegfx::BColor & getBColor() const
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
constexpr tools::Long Right() const
constexpr tools::Long Top() const
sal_uInt16 GetSize() const
tools::Polygon Rect2Poly(const tools::Rectangle &rRect, const GeoStat &rGeo)
Definition: svdtrans.cxx:467
virtual SdrObjList * GetSubList() const override
Definition: svdogrp.cxx:208
virtual void NbcMove(const Size &rSiz) override
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdotxtr.cxx:94
virtual void NbcRotate(const Point &rRef, Degree100 nAngle, double sn, double cs) override
Definition: svdotxtr.cxx:186
polygon, PolyPolygon
Abstract DrawObject.
Definition: svdobj.hxx:259
virtual SdrObject * RemoveObject(size_t nObjNum)
Definition: svdpage.cxx:407
Degree100 NormAngle36000(Degree100 a)
Normalize angle to -180.00..179.99.
Definition: svdtrans.cxx:408
virtual Degree100 GetRotateAngle() const override
Definition: svdotxtr.cxx:84
constexpr tools::Long Bottom() const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:101
sal_Int32 GetDenominator() const
B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon &rCandidate, double fAngleBound)
virtual Degree100 GetShearAngle(bool bVertical=false) const override
Definition: svdotxtr.cxx:89
sal_Int32 GetNumerator() const
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
Definition: svdobj.hxx:97
SdrOnOffItem makeSdrShadowItem(bool bShadow)
Definition: sdshitm.hxx:25
void NbcSetStyleSheet(SfxStyleSheet *pNewStyleSheet, bool bDontRemoveHardAttr)
Definition: svdobj.cxx:2260
virtual void NbcSetLogicRect(const tools::Rectangle &rRect) override
Definition: svdotxtr.cxx:74
virtual SdrObjectUniquePtr DoConvertToPolyObj(bool bBezier, bool bAddText) const override
Definition: svdotxtr.cxx:408
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdotxtr.cxx:42
virtual const tools::Rectangle & GetLogicRect() const override
Definition: svdotxtr.cxx:69
virtual void NbcSetLayer(SdrLayerID nLayer)
Definition: svdobj.cxx:685