LibreOffice Module svx (master)  1
sdrdecompositiontools.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 
40 #include <svx/svdotext.hxx>
52 #include <sal/log.hxx>
53 
54 
55 using namespace com::sun::star;
56 
57 
59 {
60 
61  class TransparencePrimitive2D;
62 
64  const basegfx::B2DPolyPolygon& rPolyPolygon,
65  const attribute::SdrFillAttribute& rFill,
66  const attribute::FillGradientAttribute& rFillGradient)
67  {
68  // when we have no given definition range, use the range of the given geometry
69  // also for definition (simplest case)
70  const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
71 
73  rPolyPolygon,
74  aRange,
75  rFill,
76  rFillGradient);
77  }
78 
80  const basegfx::B2DPolyPolygon& rPolyPolygon,
81  const basegfx::B2DRange& rDefinitionRange,
82  const attribute::SdrFillAttribute& rFill,
83  const attribute::FillGradientAttribute& rFillGradient)
84  {
86  {
87  return Primitive2DReference();
88  }
89 
90  // prepare fully scaled polygon
91  BasePrimitive2D* pNewFillPrimitive = nullptr;
92 
93  if(!rFill.getGradient().isDefault())
94  {
95  pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
96  rPolyPolygon,
97  rDefinitionRange,
98  rFill.getGradient());
99  }
100  else if(!rFill.getHatch().isDefault())
101  {
102  pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(
103  rPolyPolygon,
104  rDefinitionRange,
105  rFill.getColor(),
106  rFill.getHatch());
107  }
108  else if(!rFill.getFillGraphic().isDefault())
109  {
110  pNewFillPrimitive = new PolyPolygonGraphicPrimitive2D(
111  rPolyPolygon,
112  rDefinitionRange,
113  rFill.getFillGraphic().createFillGraphicAttribute(rDefinitionRange));
114  }
115  else
116  {
117  pNewFillPrimitive = new PolyPolygonColorPrimitive2D(
118  rPolyPolygon,
119  rFill.getColor());
120  }
121 
122  if(0.0 != rFill.getTransparence())
123  {
124  // create simpleTransparencePrimitive, add created fill primitive
125  const Primitive2DReference xRefA(pNewFillPrimitive);
126  const Primitive2DContainer aContent { xRefA };
128  }
129  else if(!rFillGradient.isDefault())
130  {
131  // create sequence with created fill primitive
132  const Primitive2DReference xRefA(pNewFillPrimitive);
133  const Primitive2DContainer aContent { xRefA };
134 
135  // create FillGradientPrimitive2D for transparence and add to new sequence
136  // fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways
137  const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
138  const Primitive2DReference xRefB(
140  aRange,
141  rDefinitionRange,
142  rFillGradient));
143  const Primitive2DContainer aAlpha { xRefB };
144 
145  // create TransparencePrimitive2D using alpha and content
146  return Primitive2DReference(new TransparencePrimitive2D(aContent, aAlpha));
147  }
148  else
149  {
150  // add to decomposition
151  return Primitive2DReference(pNewFillPrimitive);
152  }
153  }
154 
156  const basegfx::B2DPolygon& rPolygon,
157  const attribute::SdrLineAttribute& rLine,
159  {
160  // create line and stroke attribute
161  const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
162  const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
163  BasePrimitive2D* pNewLinePrimitive = nullptr;
164 
165  if(!rPolygon.isClosed() && !rStroke.isDefault())
166  {
168  attribute::LineStartEndAttribute aEnd(rStroke.getEndWidth(), rStroke.getEndPolyPolygon(), rStroke.isEndCentered());
169 
170  // create data
171  pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd);
172  }
173  else
174  {
175  // create data
176  pNewLinePrimitive = new PolygonStrokePrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute);
177  }
178 
179  if(0.0 != rLine.getTransparence())
180  {
181  // create simpleTransparencePrimitive, add created fill primitive
182  const Primitive2DReference xRefA(pNewLinePrimitive);
183  const Primitive2DContainer aContent { xRefA };
185  }
186  else
187  {
188  // add to decomposition
189  return Primitive2DReference(pNewLinePrimitive);
190  }
191  }
192 
194  const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
195  const basegfx::B2DHomMatrix& rObjectTransform,
196  const attribute::SdrTextAttribute& rText,
197  const attribute::SdrLineAttribute& rStroke,
198  bool bCellText,
199  bool bWordWrap)
200  {
201  basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform);
202  std::unique_ptr<SdrTextPrimitive2D> pNew;
203 
204  if(rText.isContour())
205  {
206  // contour text
207  if(!rStroke.isDefault() && 0.0 != rStroke.getWidth())
208  {
209  // take line width into account and shrink contour polygon accordingly
210  // decompose to get scale
211  basegfx::B2DVector aScale, aTranslate;
212  double fRotate, fShearX;
213  rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
214 
215  // scale outline to object's size to allow growing with value relative to that size
216  // and also to keep aspect ratio
217  basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
218  aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
219  fabs(aScale.getX()), fabs(aScale.getY())));
220 
221  // grow the polygon. To shrink, use negative value (half width)
222  aScaledUnitPolyPolygon = basegfx::utils::growInNormalDirection(aScaledUnitPolyPolygon, -(rStroke.getWidth() * 0.5));
223 
224  // scale back to unit polygon
225  aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
226  0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0,
227  0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0));
228 
229  // create with unit polygon
230  pNew.reset(new SdrContourTextPrimitive2D(
231  &rText.getSdrText(),
232  rText.getOutlinerParaObject(),
233  aScaledUnitPolyPolygon,
234  rObjectTransform));
235  }
236  else
237  {
238  // create with unit polygon
239  pNew.reset(new SdrContourTextPrimitive2D(
240  &rText.getSdrText(),
241  rText.getOutlinerParaObject(),
242  rUnitPolyPolygon,
243  rObjectTransform));
244  }
245  }
246  else if(!rText.getSdrFormTextAttribute().isDefault())
247  {
248  // text on path, use scaled polygon
249  basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
250  aScaledPolyPolygon.transform(rObjectTransform);
251  pNew.reset(new SdrPathTextPrimitive2D(
252  &rText.getSdrText(),
253  rText.getOutlinerParaObject(),
254  aScaledPolyPolygon,
255  rText.getSdrFormTextAttribute()));
256  }
257  else
258  {
259  // rObjectTransform is the whole SdrObject transformation from unit rectangle
260  // to its size and position. Decompose to allow working with single values.
261  basegfx::B2DVector aScale, aTranslate;
262  double fRotate, fShearX;
263  rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
264 
265  // extract mirroring
266  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
267  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
268  aScale = basegfx::absolute(aScale);
269 
270  // Get the real size, since polygon outline and scale
271  // from the object transformation may vary (e.g. ellipse segments)
272  basegfx::B2DHomMatrix aJustScaleTransform;
273  aJustScaleTransform.set(0, 0, aScale.getX());
274  aJustScaleTransform.set(1, 1, aScale.getY());
275  basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
276  aScaledUnitPolyPolygon.transform(aJustScaleTransform);
277  const basegfx::B2DRange aSnapRange(basegfx::utils::getRange(aScaledUnitPolyPolygon));
278 
279  // create a range describing the wanted text position and size (aTextAnchorRange). This
280  // means to use the text distance values here
281  const basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + rText.getTextLeftDistance(), aSnapRange.getMinY() + rText.getTextUpperDistance());
282  const basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - rText.getTextRightDistance(), aSnapRange.getMaxY() - rText.getTextLowerDistance());
283  basegfx::B2DRange aTextAnchorRange;
284  aTextAnchorRange.expand(aTopLeft);
285  aTextAnchorRange.expand(aBottomRight);
286 
287  // now create a transformation from this basic range (aTextAnchorRange)
288  // #i121494# if we have no scale use at least 1.0 to have a carrier e.g. for
289  // mirror values, else these will get lost
291  basegfx::fTools::equalZero(aTextAnchorRange.getWidth()) ? 1.0 : aTextAnchorRange.getWidth(),
292  basegfx::fTools::equalZero(aTextAnchorRange.getHeight()) ? 1.0 : aTextAnchorRange.getHeight(),
293  aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY());
294 
295  // apply mirroring
296  aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
297 
298  // apply object's other transforms
299  aAnchorTransform = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
300  * aAnchorTransform;
301 
302  if(rText.isFitToSize())
303  {
304  // stretched text in range
305  pNew.reset(new SdrStretchTextPrimitive2D(
306  &rText.getSdrText(),
307  rText.getOutlinerParaObject(),
308  aAnchorTransform,
309  rText.isFixedCellHeight()));
310  }
311  else if(rText.isAutoFit())
312  {
313  // isotropically scaled text in range
314  pNew.reset(new SdrAutoFitTextPrimitive2D(
315  &rText.getSdrText(),
316  rText.getOutlinerParaObject(),
317  aAnchorTransform,
318  bWordWrap));
319  }
320  else if( rText.isChainable() && !rText.isInEditMode() )
321  {
322  pNew.reset(new SdrChainedTextPrimitive2D(
323  &rText.getSdrText(),
324  rText.getOutlinerParaObject(),
325  aAnchorTransform ));
326  }
327  else // text in range
328  {
329  // build new primitive
330  pNew.reset(new SdrBlockTextPrimitive2D(
331  &rText.getSdrText(),
332  rText.getOutlinerParaObject(),
333  aAnchorTransform,
334  rText.getSdrTextHorzAdjust(),
335  rText.getSdrTextVertAdjust(),
336  rText.isFixedCellHeight(),
337  rText.isScroll(),
338  bCellText,
339  bWordWrap));
340  }
341  }
342 
343  OSL_ENSURE(pNew != nullptr, "createTextPrimitive: no text primitive created (!)");
344 
345  if(rText.isBlink())
346  {
347  // prepare animation and primitive list
349  rText.getBlinkTextTiming(aAnimationList);
350 
351  if(0.0 != aAnimationList.getDuration())
352  {
353  // create content sequence
354  const Primitive2DReference xRefA(pNew.release());
355  const Primitive2DContainer aContent { xRefA };
356 
357  // create and add animated switch primitive
358  return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, aContent));
359  }
360  else
361  {
362  // add to decomposition
363  return Primitive2DReference(pNew.release());
364  }
365  }
366 
367  if(rText.isScroll())
368  {
369  // suppress scroll when FontWork
370  if(rText.getSdrFormTextAttribute().isDefault())
371  {
372  // get scroll direction
373  const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection());
374  const bool bHorizontal(SdrTextAniDirection::Left == eDirection || SdrTextAniDirection::Right == eDirection);
375 
376  // decompose to get separated values for the scroll box
377  basegfx::B2DVector aScale, aTranslate;
378  double fRotate, fShearX;
379  aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX);
380 
381  // build transform from scaled only to full AnchorTransform and inverse
383  fShearX, fRotate, aTranslate));
384  basegfx::B2DHomMatrix aISRT(aSRT);
385  aISRT.invert();
386 
387  // bring the primitive back to scaled only and get scaled range, create new clone for this
388  std::unique_ptr<SdrTextPrimitive2D> pNew2 = pNew->createTransformedClone(aISRT);
389  OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)");
390  pNew = std::move(pNew2);
391 
392  // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay
393  // since the decompose is view-independent
394  const uno::Sequence< beans::PropertyValue > xViewParameters;
395  geometry::ViewInformation2D aViewInformation2D(xViewParameters);
396 
397  // get range
398  const basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D));
399 
400  // create left outside and right outside transformations. Also take care
401  // of the clip rectangle
402  basegfx::B2DHomMatrix aLeft, aRight;
403  basegfx::B2DPoint aClipTopLeft(0.0, 0.0);
404  basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY());
405 
406  if(bHorizontal)
407  {
408  aClipTopLeft.setY(aScaledRange.getMinY());
409  aClipBottomRight.setY(aScaledRange.getMaxY());
410  aLeft.translate(-aScaledRange.getMaxX(), 0.0);
411  aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0);
412  }
413  else
414  {
415  aClipTopLeft.setX(aScaledRange.getMinX());
416  aClipBottomRight.setX(aScaledRange.getMaxX());
417  aLeft.translate(0.0, -aScaledRange.getMaxY());
418  aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY());
419  }
420 
421  aLeft *= aSRT;
422  aRight *= aSRT;
423 
424  // prepare animation list
426 
427  if(bHorizontal)
428  {
429  rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth());
430  }
431  else
432  {
433  rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight());
434  }
435 
436  if(0.0 != aAnimationList.getDuration())
437  {
438  // create a new Primitive2DContainer containing the animated text in its scaled only state.
439  // use the decomposition to force to simple text primitives, those will no longer
440  // need the outliner for formatting (alternatively it is also possible to just add
441  // pNew to aNewPrimitiveSequence)
442  Primitive2DContainer aAnimSequence;
443  pNew->get2DDecomposition(aAnimSequence, aViewInformation2D);
444  pNew.reset();
445 
446  // create a new animatedInterpolatePrimitive and add it
447  std::vector< basegfx::B2DHomMatrix > aMatrixStack;
448  aMatrixStack.push_back(aLeft);
449  aMatrixStack.push_back(aRight);
450  const Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D(aMatrixStack, aAnimationList, aAnimSequence));
451  const Primitive2DContainer aContent { xRefA };
452 
453  // scrolling needs an encapsulating clipping primitive
454  const basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight);
456  aClipPolygon.transform(aSRT);
457  return Primitive2DReference(new MaskPrimitive2D(basegfx::B2DPolyPolygon(aClipPolygon), aContent));
458  }
459  else
460  {
461  // add to decomposition
462  return Primitive2DReference(pNew.release());
463  }
464  }
465  }
466 
467  if(rText.isInEditMode())
468  {
469  // #i97628#
470  // encapsulate with TextHierarchyEditPrimitive2D to allow renderers
471  // to suppress actively edited content if needed
472  const Primitive2DReference xRefA(pNew.release());
473  const Primitive2DContainer aContent { xRefA };
474 
475  // create and add TextHierarchyEditPrimitive2D primitive
477  }
478  else
479  {
480  // add to decomposition
481  return Primitive2DReference(pNew.release());
482  }
483  }
484 
486  const Primitive2DContainer& rContent,
487  const attribute::SdrShadowAttribute& rShadow,
488  const basegfx::B2DHomMatrix& rObjectMatrix)
489  {
490  if(!rContent.empty())
491  {
492  Primitive2DContainer aRetval(2);
493  basegfx::B2DHomMatrix aShadowOffset;
494 
495  {
496  if(rShadow.getSize().getX() != 100000)
497  {
498  basegfx::B2DTuple aScale;
499  basegfx::B2DTuple aTranslate;
500  double fRotate = 0;
501  double fShearX = 0;
502  rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
503  // Scale the shadow
504  double nTranslateX = aTranslate.getX();
505  double nTranslateY = aTranslate.getY();
506 
507  // The origin for scaling is the top left corner by default. A negative
508  // shadow offset changes the origin.
509  if (rShadow.getOffset().getX() < 0)
510  nTranslateX += aScale.getX();
511  if (rShadow.getOffset().getY() < 0)
512  nTranslateY += aScale.getY();
513 
514  aShadowOffset.translate(-nTranslateX, -nTranslateY);
515  aShadowOffset.scale(rShadow.getSize().getX() * 0.00001, rShadow.getSize().getY() * 0.00001);
516  aShadowOffset.translate(nTranslateX, nTranslateY);
517  }
518 
519  aShadowOffset.translate(rShadow.getOffset().getX(), rShadow.getOffset().getY());
520  }
521 
522  // create shadow primitive and add content
523  aRetval[0] = Primitive2DReference(
524  new ShadowPrimitive2D(
525  aShadowOffset,
526  rShadow.getColor(),
527  rShadow.getBlur(),
528  rContent));
529 
530  if(0.0 != rShadow.getTransparence())
531  {
532  // create SimpleTransparencePrimitive2D
533  const Primitive2DContainer aTempContent { aRetval[0] };
534 
535  aRetval[0] = Primitive2DReference(
537  aTempContent,
538  rShadow.getTransparence()));
539  }
540 
541  aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent));
542  return aRetval;
543  }
544  else
545  {
546  return rContent;
547  }
548  }
549 
551  const Primitive2DContainer& rContent,
552  const attribute::SdrGlowAttribute& rGlow)
553  {
554  if(rContent.empty())
555  return rContent;
556  Primitive2DContainer aRetval(2);
557  aRetval[0] = Primitive2DReference(
558  new GlowPrimitive2D(rGlow.getColor(), rGlow.getRadius(), rContent));
559  aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent));
560  return aRetval;
561  }
562 
564  sal_Int32 nRadius)
565  {
566  if (rContent.empty() || !nRadius)
567  return rContent;
568  Primitive2DContainer aRetval(1);
569  aRetval[0] = Primitive2DReference(new SoftEdgePrimitive2D(nRadius, rContent));
570  return aRetval;
571  }
572 
573 } // end of namespace
574 
575 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool moreOrEqual(const double &rfValA, const double &rfValB)
B2DPolygon growInNormalDirection(const B2DPolygon &rCandidate, double fValue)
const FillGradientAttribute & getGradient() const
void setX(double fX)
void expand(const B2DTuple &rTuple)
Primitive2DContainer createEmbeddedGlowPrimitive(const Primitive2DContainer &rContent, const attribute::SdrGlowAttribute &rGlow)
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
css::drawing::LineCap getCap() const
B2DTuple absolute(const B2DTuple &rTup)
const basegfx::BColor & getColor() const
double getX() const
double getY() const
const basegfx::BColor & getColor() const
double getMaxX() const
const basegfx::B2DPolyPolygon & getStartPolyPolygon() const
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
basegfx::B2DLineJoin getJoin() const
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
const FillHatchAttribute & getHatch() const
Primitive2DReference createPolyPolygonFillPrimitive(const basegfx::B2DPolyPolygon &rPolyPolygon, const basegfx::B2DRange &rDefinitionRange, const attribute::SdrFillAttribute &rFill, const attribute::FillGradientAttribute &rFillGradient)
SdrTextHorzAdjust getSdrTextHorzAdjust() const
double getMaxY() const
bool isClosed() const
const OutlinerParaObject & getOutlinerParaObject() const
static bool less(const double &rfValA, const double &rfValB)
FillGraphicAttribute createFillGraphicAttribute(const basegfx::B2DRange &rRange) const
const basegfx::B2DPolyPolygon & getEndPolyPolygon() const
void getScrollTextTiming(drawinglayer::animation::AnimationEntryList &rAnimList, double fFrameLength, double fTextLength) const
virtual double getDuration() const override
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
SdrTextObj & GetObject() const
Definition: svdtext.hxx:64
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
const basegfx::B2DVector & getOffset() const
const ::std::vector< double > & getDotDashArray() const
static bool equalZero(const double &rfVal)
const basegfx::BColor & getColor() const
void scale(double fX, double fY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
Primitive2DReference createTextPrimitive(const basegfx::B2DPolyPolygon &rUnitPolyPolygon, const basegfx::B2DHomMatrix &rObjectTransform, const attribute::SdrTextAttribute &rText, const attribute::SdrLineAttribute &rStroke, bool bCellText, bool bWordWrap)
B2DRange getRange(const B2DPolygon &rCandidate)
void transform(const basegfx::B2DHomMatrix &rMatrix)
Primitive2DContainer createEmbeddedShadowPrimitive(const Primitive2DContainer &rContent, const attribute::SdrShadowAttribute &rShadow, const basegfx::B2DHomMatrix &rObjectMatrix)
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
double getMinY() const
void setY(double fY)
void getBlinkTextTiming(drawinglayer::animation::AnimationEntryList &rAnimList) const
Primitive2DContainer createEmbeddedSoftEdgePrimitive(const Primitive2DContainer &rContent, sal_Int32 nRadius)
SdrTextAniDirection GetTextAniDirection() const
Definition: svdotext.cxx:1767
void translate(double fX, double fY)
SdrTextAniDirection
Definition: sdtaditm.hxx:29
const SdrFormTextAttribute & getSdrFormTextAttribute() const
double getMinX() const
const SdrFillGraphicAttribute & getFillGraphic() const
SdrTextVertAdjust getSdrTextVertAdjust() const
const basegfx::B2DVector & getSize() const
B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
Primitive2DReference createPolygonLinePrimitive(const basegfx::B2DPolygon &rPolygon, const attribute::SdrLineAttribute &rLine, const attribute::SdrLineStartEndAttribute &rStroke)