LibreOffice Module svx (master)  1
svdotextdecomposition.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/svdetc.hxx>
22 #include <svx/svdoutl.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/svdotext.hxx>
25 #include <svx/svdmodel.hxx>
26 #include <textchain.hxx>
27 #include <textchainflow.hxx>
28 #include <svx/sdtacitm.hxx>
29 #include <svx/sdtayitm.hxx>
30 #include <svx/sdtaiitm.hxx>
31 #include <svx/sdtaaitm.hxx>
32 #include <svx/xfillit0.hxx>
38 #include <editeng/eeitem.hxx>
39 #include <editeng/editstat.hxx>
40 #include <tools/helpers.hxx>
41 #include <svl/itemset.hxx>
43 #include <basegfx/color/bcolor.hxx>
44 #include <vcl/svapp.hxx>
46 #include <editeng/svxenum.hxx>
47 #include <editeng/flditem.hxx>
48 #include <editeng/adjustitem.hxx>
54 #include <svx/unoapi.hxx>
56 #include <editeng/outlobj.hxx>
58 #include <sal/log.hxx>
59 
60 using namespace com::sun::star;
61 
62 // helpers
63 
64 namespace
65 {
66  class impTextBreakupHandler
67  {
68  private:
72 
73  SdrOutliner& mrOutliner;
74  basegfx::B2DHomMatrix maNewTransformA;
75  basegfx::B2DHomMatrix maNewTransformB;
76 
77  // the visible area for contour text decomposition
78  basegfx::B2DVector maScale;
79 
80  // ClipRange for BlockText decomposition; only text portions completely
81  // inside are to be accepted, so this is different from geometric clipping
82  // (which would allow e.g. upper parts of portions to remain). Only used for
83  // BlockText (see there)
84  basegfx::B2DRange maClipRange;
85 
86  DECL_LINK(decomposeContourTextPrimitive, DrawPortionInfo*, void);
87  DECL_LINK(decomposeBlockTextPrimitive, DrawPortionInfo*, void);
88  DECL_LINK(decomposeStretchTextPrimitive, DrawPortionInfo*, void);
89 
90  DECL_LINK(decomposeContourBulletPrimitive, DrawBulletInfo*, void);
91  DECL_LINK(decomposeBlockBulletPrimitive, DrawBulletInfo*, void);
92  DECL_LINK(decomposeStretchBulletPrimitive, DrawBulletInfo*, void);
93 
94  void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
95  static drawinglayer::primitive2d::BasePrimitive2D* impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo);
96  void impFlushTextPortionPrimitivesToLinePrimitives();
97  void impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara);
98  void impHandleDrawPortionInfo(const DrawPortionInfo& rInfo);
99  void impHandleDrawBulletInfo(const DrawBulletInfo& rInfo);
100 
101  public:
102  explicit impTextBreakupHandler(SdrOutliner& rOutliner)
103  : maTextPortionPrimitives(),
104  maLinePrimitives(),
105  maParagraphPrimitives(),
106  mrOutliner(rOutliner),
107  maNewTransformA(),
108  maNewTransformB(),
109  maScale(),
110  maClipRange()
111  {
112  }
113 
114  void decomposeContourTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB, const basegfx::B2DVector& rScale)
115  {
116  maScale = rScale;
117  maNewTransformA = rNewTransformA;
118  maNewTransformB = rNewTransformB;
119  mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeContourTextPrimitive));
120  mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeContourBulletPrimitive));
121  mrOutliner.StripPortions();
124  }
125 
126  void decomposeBlockTextPrimitive(
127  const basegfx::B2DHomMatrix& rNewTransformA,
128  const basegfx::B2DHomMatrix& rNewTransformB,
129  const basegfx::B2DRange& rClipRange)
130  {
131  maNewTransformA = rNewTransformA;
132  maNewTransformB = rNewTransformB;
133  maClipRange = rClipRange;
134  mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeBlockTextPrimitive));
135  mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeBlockBulletPrimitive));
136  mrOutliner.StripPortions();
139  }
140 
141  void decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB)
142  {
143  maNewTransformA = rNewTransformA;
144  maNewTransformB = rNewTransformB;
145  mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeStretchTextPrimitive));
146  mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeStretchBulletPrimitive));
147  mrOutliner.StripPortions();
150  }
151 
152  drawinglayer::primitive2d::Primitive2DContainer const & getPrimitive2DSequence();
153  };
154 
155  void impTextBreakupHandler::impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo)
156  {
157  if(rInfo.maText.isEmpty() || !rInfo.mnTextLen)
158  return;
159 
160  OUString caseMappedText = rInfo.mrFont.CalcCaseMap( rInfo.maText );
161  basegfx::B2DVector aFontScaling;
164  aFontScaling,
165  rInfo.mrFont,
166  rInfo.IsRTL(),
167  false));
168  basegfx::B2DHomMatrix aNewTransform;
169 
170  // add font scale to new transform
171  aNewTransform.scale(aFontScaling.getX(), aFontScaling.getY());
172 
173  // look for proportional font scaling, if necessary, scale accordingly
174  sal_Int8 nPropr(rInfo.mrFont.GetPropr());
175  if(100 != nPropr)
176  {
177  const double fFactor(rInfo.mrFont.GetPropr() / 100.0);
178  aNewTransform.scale(fFactor, fFactor);
179  }
180 
181  // apply font rotate
182  if(rInfo.mrFont.GetOrientation())
183  {
184  aNewTransform.rotate(-rInfo.mrFont.GetOrientation() * F_PI1800);
185  }
186 
187  // look for escapement, if necessary, translate accordingly
188  if(rInfo.mrFont.GetEscapement())
189  {
190  sal_Int16 nEsc(rInfo.mrFont.GetEscapement());
191 
192  if(DFLT_ESC_AUTO_SUPER == nEsc)
193  {
194  nEsc = .8 * (100 - nPropr);
195  assert (nEsc == DFLT_ESC_SUPER && "I'm sure this formula needs to be changed, but how to confirm that???");
196  nEsc = DFLT_ESC_SUPER;
197  }
198  else if(DFLT_ESC_AUTO_SUB == nEsc)
199  {
200  nEsc = .2 * -(100 - nPropr);
201  assert (nEsc == -20 && "I'm sure this formula needs to be changed, but how to confirm that???");
202  nEsc = -20;
203  }
204 
205  if(nEsc > MAX_ESC_POS)
206  {
207  nEsc = MAX_ESC_POS;
208  }
209  else if(nEsc < -MAX_ESC_POS)
210  {
211  nEsc = -MAX_ESC_POS;
212  }
213 
214  const double fEscapement(nEsc / -100.0);
215  aNewTransform.translate(0.0, fEscapement * aFontScaling.getY());
216  }
217 
218  // apply transformA
219  aNewTransform *= maNewTransformA;
220 
221  // apply local offset
222  aNewTransform.translate(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y());
223 
224  // also apply embedding object's transform
225  aNewTransform *= maNewTransformB;
226 
227  // prepare DXArray content. To make it independent from font size (and such from
228  // the text transformation), scale it to unit coordinates
229  ::std::vector< double > aDXArray;
230 
231  if(rInfo.mpDXArray && rInfo.mnTextLen)
232  {
233  aDXArray.reserve(rInfo.mnTextLen);
234 
235  for(sal_Int32 a=0; a < rInfo.mnTextLen; a++)
236  {
237  aDXArray.push_back(static_cast<double>(rInfo.mpDXArray[a]));
238  }
239  }
240 
241  // create complex text primitive and append
242  const Color aFontColor(rInfo.mrFont.GetColor());
243  const basegfx::BColor aBFontColor(aFontColor.getBColor());
244 
245  const Color aTextFillColor(rInfo.mrFont.GetFillColor());
246 
247  // prepare wordLineMode (for underline and strikeout)
248  // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)'
249  // to be split which would not look like the original
250  const bool bWordLineMode(rInfo.mrFont.IsWordLineMode() && !rInfo.mbEndOfBullet);
251 
252  // prepare new primitive
253  drawinglayer::primitive2d::BasePrimitive2D* pNewPrimitive = nullptr;
254  const bool bDecoratedIsNeeded(
255  LINESTYLE_NONE != rInfo.mrFont.GetOverline()
256  || LINESTYLE_NONE != rInfo.mrFont.GetUnderline()
257  || STRIKEOUT_NONE != rInfo.mrFont.GetStrikeout()
258  || FontEmphasisMark::NONE != (rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::Style)
259  || FontRelief::NONE != rInfo.mrFont.GetRelief()
260  || rInfo.mrFont.IsShadow()
261  || bWordLineMode);
262 
263  if(bDecoratedIsNeeded)
264  {
265  // TextDecoratedPortionPrimitive2D needed, prepare some more data
266  // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead
267  const Color aUnderlineColor(rInfo.maTextLineColor);
268  const basegfx::BColor aBUnderlineColor((Color(0xffffffff) == aUnderlineColor) ? aBFontColor : aUnderlineColor.getBColor());
269  const Color aOverlineColor(rInfo.maOverlineColor);
270  const basegfx::BColor aBOverlineColor((Color(0xffffffff) == aOverlineColor) ? aBFontColor : aOverlineColor.getBColor());
271 
272  // prepare overline and underline data
273  const drawinglayer::primitive2d::TextLine eFontOverline(
275  const drawinglayer::primitive2d::TextLine eFontLineStyle(
277 
278  // check UnderlineAbove
279  const bool bUnderlineAbove(
280  drawinglayer::primitive2d::TEXT_LINE_NONE != eFontLineStyle && rInfo.mrFont.IsUnderlineAbove());
281 
282  // prepare strikeout data
283  const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(
285 
286  // prepare emphasis mark data
288 
289  switch(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::Style)
290  {
291  case FontEmphasisMark::Dot : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DOT; break;
292  case FontEmphasisMark::Circle : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_CIRCLE; break;
293  case FontEmphasisMark::Disc : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DISC; break;
294  case FontEmphasisMark::Accent : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_ACCENT; break;
295  default: break;
296  }
297 
298  const bool bEmphasisMarkAbove(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::PosAbove);
299  const bool bEmphasisMarkBelow(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::PosBelow);
300 
301  // prepare font relief data
303 
304  switch(rInfo.mrFont.GetRelief())
305  {
306  case FontRelief::Embossed : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
307  case FontRelief::Engraved : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
308  default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
309  }
310 
311  // prepare shadow/outline data
312  const bool bShadow(rInfo.mrFont.IsShadow());
313 
314  // TextDecoratedPortionPrimitive2D is needed, create one
316 
317  // attributes for TextSimplePortionPrimitive2D
318  aNewTransform,
319  caseMappedText,
320  rInfo.mnTextStart,
321  rInfo.mnTextLen,
322  aDXArray,
323  aFontAttribute,
324  rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
325  aBFontColor,
326  aTextFillColor,
327 
328  // attributes for TextDecoratedPortionPrimitive2D
329  aBOverlineColor,
330  aBUnderlineColor,
331  eFontOverline,
332  eFontLineStyle,
333  bUnderlineAbove,
334  eTextStrikeout,
335  bWordLineMode,
336  eTextEmphasisMark,
337  bEmphasisMarkAbove,
338  bEmphasisMarkBelow,
339  eTextRelief,
340  bShadow);
341  }
342  else
343  {
344  // TextSimplePortionPrimitive2D is enough
346  aNewTransform,
347  caseMappedText,
348  rInfo.mnTextStart,
349  rInfo.mnTextLen,
350  aDXArray,
351  aFontAttribute,
352  rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
353  aBFontColor,
354  rInfo.mbFilled,
355  rInfo.mnWidthToFill,
356  aTextFillColor);
357  }
358 
359  if (aFontColor.GetTransparency() != 0)
360  {
361  // Handle semi-transparent text for both the decorated and simple case here.
364  aFontColor.GetTransparency() / 255.0);
365  }
366 
367  if(rInfo.mbEndOfBullet)
368  {
369  // embed in TextHierarchyBulletPrimitive2D
370  const drawinglayer::primitive2d::Primitive2DReference aNewReference(pNewPrimitive);
371  const drawinglayer::primitive2d::Primitive2DContainer aNewSequence { aNewReference } ;
372  pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence);
373  }
374 
375  if(rInfo.mpFieldData)
376  {
377  pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive, rInfo);
378  }
379 
380  maTextPortionPrimitives.push_back(pNewPrimitive);
381 
382  // support for WrongSpellVector. Create WrongSpellPrimitives as needed
383  if(rInfo.mpWrongSpellVector && !aDXArray.empty())
384  {
385  const sal_Int32 nSize(rInfo.mpWrongSpellVector->size());
386  const sal_Int32 nDXCount(aDXArray.size());
387  const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
388 
389  for(sal_Int32 a(0); a < nSize; a++)
390  {
391  const EEngineData::WrongSpellClass& rCandidate = (*rInfo.mpWrongSpellVector)[a];
392 
393  if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
394  {
395  const sal_Int32 nStart(rCandidate.nStart - rInfo.mnTextStart);
396  const sal_Int32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
397  double fStart(0.0);
398  double fEnd(0.0);
399 
400  if(nStart > 0 && nStart - 1 < nDXCount)
401  {
402  fStart = aDXArray[nStart - 1];
403  }
404 
405  if(nEnd > 0 && nEnd - 1 < nDXCount)
406  {
407  fEnd = aDXArray[nEnd - 1];
408  }
409 
410  if(!basegfx::fTools::equal(fStart, fEnd))
411  {
412  if(rInfo.IsRTL())
413  {
414  // #i98523#
415  // When the portion is RTL, mirror the redlining using the
416  // full portion width
417  const double fTextWidth(aDXArray[aDXArray.size() - 1]);
418 
419  fStart = fTextWidth - fStart;
420  fEnd = fTextWidth - fEnd;
421  }
422 
423  // need to take FontScaling out of values; it's already part of
424  // aNewTransform and would be double applied
425  const double fFontScaleX(aFontScaling.getX());
426 
427  if(!basegfx::fTools::equal(fFontScaleX, 1.0)
428  && !basegfx::fTools::equalZero(fFontScaleX))
429  {
430  fStart /= fFontScaleX;
431  fEnd /= fFontScaleX;
432  }
433 
434  maTextPortionPrimitives.push_back(new drawinglayer::primitive2d::WrongSpellPrimitive2D(
435  aNewTransform,
436  fStart,
437  fEnd,
438  aSpellColor));
439  }
440  }
441  }
442  }
443  }
444 
445  drawinglayer::primitive2d::BasePrimitive2D* impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo)
446  {
447  if(rInfo.mpFieldData)
448  {
449  // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D
450  // which holds the field type and, if applicable, the URL
451  const SvxURLField* pURLField = dynamic_cast< const SvxURLField* >(rInfo.mpFieldData);
452  const SvxPageField* pPageField = dynamic_cast< const SvxPageField* >(rInfo.mpFieldData);
453 
454  // embed current primitive to a sequence
456 
457  if(pPrimitive)
458  {
459  aSequence.resize(1);
460  aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive);
461  }
462 
463  if(pURLField)
464  {
465  // extended this to hold more of the contents of the original
466  // SvxURLField since that stuff is still used in HitTest and e.g. Calc
467  std::vector< std::pair< OUString, OUString>> meValues;
468  meValues.emplace_back("URL", pURLField->GetURL());
469  meValues.emplace_back("Representation", pURLField->GetRepresentation());
470  meValues.emplace_back("TargetFrame", pURLField->GetTargetFrame());
471  meValues.emplace_back("SvxURLFormat", OUString::number(static_cast<sal_uInt16>(pURLField->GetFormat())));
473  }
474  else if(pPageField)
475  {
477  }
478  else
479  {
481  }
482  }
483 
484  return pPrimitive;
485  }
486 
487  void impTextBreakupHandler::impFlushTextPortionPrimitivesToLinePrimitives()
488  {
489  // only create a line primitive when we had content; there is no need for
490  // empty line primitives (contrary to paragraphs, see below).
491  if(!maTextPortionPrimitives.empty())
492  {
493  maLinePrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyLinePrimitive2D(maTextPortionPrimitives));
494  maTextPortionPrimitives.clear();
495  }
496  }
497 
498  void impTextBreakupHandler::impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara)
499  {
500  sal_Int16 nDepth = mrOutliner.GetDepth(nPara);
501  EBulletInfo eInfo = mrOutliner.GetBulletInfo(nPara);
502  // Pass -1 to signal VclMetafileProcessor2D that there is no active
503  // bullets/numbering in this paragraph (i.e. this is normal text)
504  const sal_Int16 nOutlineLevel( eInfo.bVisible ? nDepth : -1);
505 
506  // ALWAYS create a paragraph primitive, even when no content was added. This is done to
507  // have the correct paragraph count even with empty paragraphs. Those paragraphs will
508  // have an empty sub-PrimitiveSequence.
509  maParagraphPrimitives.push_back(
511  maLinePrimitives,
512  nOutlineLevel));
513  maLinePrimitives.clear();
514  }
515 
516  void impTextBreakupHandler::impHandleDrawPortionInfo(const DrawPortionInfo& rInfo)
517  {
518  impCreateTextPortionPrimitive(rInfo);
519 
520  if(rInfo.mbEndOfLine || rInfo.mbEndOfParagraph)
521  {
522  impFlushTextPortionPrimitivesToLinePrimitives();
523  }
524 
525  if(rInfo.mbEndOfParagraph)
526  {
527  impFlushLinePrimitivesToParagraphPrimitives(rInfo.mnPara);
528  }
529  }
530 
531  void impTextBreakupHandler::impHandleDrawBulletInfo(const DrawBulletInfo& rInfo)
532  {
533  basegfx::B2DHomMatrix aNewTransform;
534 
535  // add size to new transform
536  aNewTransform.scale(rInfo.maBulletSize.getWidth(), rInfo.maBulletSize.getHeight());
537 
538  // apply transformA
539  aNewTransform *= maNewTransformA;
540 
541  // apply local offset
542  aNewTransform.translate(rInfo.maBulletPosition.X(), rInfo.maBulletPosition.Y());
543 
544  // also apply embedding object's transform
545  aNewTransform *= maNewTransformB;
546 
547  // prepare empty GraphicAttr
548  const GraphicAttr aGraphicAttr;
549 
550  // create GraphicPrimitive2D
552  aNewTransform,
553  rInfo.maBulletGraphicObject,
554  aGraphicAttr));
555 
556  // embed in TextHierarchyBulletPrimitive2D
557  const drawinglayer::primitive2d::Primitive2DContainer aNewSequence { aNewReference };
559 
560  // add to output
561  maTextPortionPrimitives.push_back(pNewPrimitive);
562  }
563 
564  IMPL_LINK(impTextBreakupHandler, decomposeContourTextPrimitive, DrawPortionInfo*, pInfo, void)
565  {
566  // for contour text, ignore (clip away) all portions which are below
567  // the visible area given by maScale
568  if(pInfo && static_cast<double>(pInfo->mrStartPos.Y()) < maScale.getY())
569  {
570  impHandleDrawPortionInfo(*pInfo);
571  }
572  }
573 
574  IMPL_LINK(impTextBreakupHandler, decomposeBlockTextPrimitive, DrawPortionInfo*, pInfo, void)
575  {
576  if(pInfo)
577  {
578  // Is clipping wanted? This is text clipping; only accept a portion
579  // if it's completely in the range
580  if(!maClipRange.isEmpty())
581  {
582  // Test start position first; this allows to not get the text range at
583  // all if text is far outside
584  const basegfx::B2DPoint aStartPosition(pInfo->mrStartPos.X(), pInfo->mrStartPos.Y());
585 
586  if(!maClipRange.isInside(aStartPosition))
587  {
588  return;
589  }
590 
591  // Start position is inside. Get TextBoundRect and TopLeft next
593  aTextLayouterDevice.setFont(pInfo->mrFont);
594 
595  const basegfx::B2DRange aTextBoundRect(
596  aTextLayouterDevice.getTextBoundRect(
597  pInfo->maText, pInfo->mnTextStart, pInfo->mnTextLen));
598  const basegfx::B2DPoint aTopLeft(aTextBoundRect.getMinimum() + aStartPosition);
599 
600  if(!maClipRange.isInside(aTopLeft))
601  {
602  return;
603  }
604 
605  // TopLeft is inside. Get BottomRight and check
606  const basegfx::B2DPoint aBottomRight(aTextBoundRect.getMaximum() + aStartPosition);
607 
608  if(!maClipRange.isInside(aBottomRight))
609  {
610  return;
611  }
612 
613  // all inside, clip was successful
614  }
615  impHandleDrawPortionInfo(*pInfo);
616  }
617  }
618 
619  IMPL_LINK(impTextBreakupHandler, decomposeStretchTextPrimitive, DrawPortionInfo*, pInfo, void)
620  {
621  if(pInfo)
622  {
623  impHandleDrawPortionInfo(*pInfo);
624  }
625  }
626 
627  IMPL_LINK(impTextBreakupHandler, decomposeContourBulletPrimitive, DrawBulletInfo*, pInfo, void)
628  {
629  if(pInfo)
630  {
631  impHandleDrawBulletInfo(*pInfo);
632  }
633  }
634 
635  IMPL_LINK(impTextBreakupHandler, decomposeBlockBulletPrimitive, DrawBulletInfo*, pInfo, void)
636  {
637  if(pInfo)
638  {
639  impHandleDrawBulletInfo(*pInfo);
640  }
641  }
642 
643  IMPL_LINK(impTextBreakupHandler, decomposeStretchBulletPrimitive, DrawBulletInfo*, pInfo, void)
644  {
645  if(pInfo)
646  {
647  impHandleDrawBulletInfo(*pInfo);
648  }
649  }
650 
651  drawinglayer::primitive2d::Primitive2DContainer const & impTextBreakupHandler::getPrimitive2DSequence()
652  {
653  if(!maTextPortionPrimitives.empty())
654  {
655  // collect non-closed lines
656  impFlushTextPortionPrimitivesToLinePrimitives();
657  }
658 
659  if(!maLinePrimitives.empty())
660  {
661  // collect non-closed paragraphs
662  impFlushLinePrimitivesToParagraphPrimitives(mrOutliner.GetParagraphCount() - 1);
663  }
664 
665  return maParagraphPrimitives;
666  }
667 } // end of anonymous namespace
668 
669 
670 // primitive decompositions
671 
674  const drawinglayer::primitive2d::SdrContourTextPrimitive2D& rSdrContourTextPrimitive,
675  const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
676 {
677  // decompose matrix to have position and size of text
678  basegfx::B2DVector aScale, aTranslate;
679  double fRotate, fShearX;
680  rSdrContourTextPrimitive.getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
681 
682  // prepare contour polygon, force to non-mirrored for laying out
683  basegfx::B2DPolyPolygon aPolyPolygon(rSdrContourTextPrimitive.getUnitPolyPolygon());
684  aPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fabs(aScale.getX()), fabs(aScale.getY())));
685 
686  // prepare outliner
687  SolarMutexGuard aSolarGuard;
688  SdrOutliner& rOutliner = ImpGetDrawOutliner();
689  const Size aNullSize;
690  rOutliner.SetPaperSize(aNullSize);
691  rOutliner.SetPolygon(aPolyPolygon);
692  rOutliner.SetUpdateMode(true);
693  rOutliner.SetText(rSdrContourTextPrimitive.getOutlinerParaObject());
694 
695  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
696  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
697 
698  // prepare matrices to apply to newly created primitives
699  basegfx::B2DHomMatrix aNewTransformA;
700 
701  // mirroring. We are now in the polygon sizes. When mirroring in X and Y,
702  // move the null point which was top left to bottom right.
703  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
704  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
705 
706  // in-between the translations of the single primitives will take place. Afterwards,
707  // the object's transformations need to be applied
709  bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
710  fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
711 
712  // now break up text primitives.
713  impTextBreakupHandler aConverter(rOutliner);
714  aConverter.decomposeContourTextPrimitive(aNewTransformA, aNewTransformB, aScale);
715 
716  // cleanup outliner
717  rOutliner.Clear();
718  rOutliner.setVisualizedPage(nullptr);
719 
720  rTarget = aConverter.getPrimitive2DSequence();
721 }
722 
725  const drawinglayer::primitive2d::SdrAutoFitTextPrimitive2D& rSdrAutofitTextPrimitive,
726  const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
727 {
728  // decompose matrix to have position and size of text
729  basegfx::B2DVector aScale, aTranslate;
730  double fRotate, fShearX;
731  rSdrAutofitTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
732 
733  // use B2DRange aAnchorTextRange for calculations
734  basegfx::B2DRange aAnchorTextRange(aTranslate);
735  aAnchorTextRange.expand(aTranslate + aScale);
736 
737  // prepare outliner
738  const SfxItemSet& rTextItemSet = rSdrAutofitTextPrimitive.getSdrText()->GetItemSet();
739  SolarMutexGuard aSolarGuard;
740  SdrOutliner& rOutliner = ImpGetDrawOutliner();
741  SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
742  SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
743  const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
744  const Size aNullSize;
745 
746  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
747  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
748 
749  rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
750  rOutliner.SetMinAutoPaperSize(aNullSize);
751  rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
752 
753  // add one to rage sizes to get back to the old Rectangle and outliner measurements
754  const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
755  const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
756  const OutlinerParaObject* pOutlinerParaObject = rSdrAutofitTextPrimitive.getSdrText()->GetOutlinerParaObject();
757  OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
758  const bool bVerticalWriting(pOutlinerParaObject->IsVertical());
759  const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
760  const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
761 
762  if(rSdrAutofitTextPrimitive.getWordWrap() || IsTextFrame())
763  {
764  rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
765  }
766 
767  if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting)
768  {
769  rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
770  }
771 
772  if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting)
773  {
774  rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
775  }
776 
777  rOutliner.SetPaperSize(aNullSize);
778  rOutliner.SetUpdateMode(true);
779  rOutliner.SetText(*pOutlinerParaObject);
780  ImpAutoFitText(rOutliner,aAnchorTextSize,bVerticalWriting);
781 
782  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
783  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
784 
785  // now get back the layouted text size from outliner
786  const Size aOutlinerTextSize(rOutliner.GetPaperSize());
787  const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
788  basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
789 
790  // correct horizontal translation using the now known text size
791  if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
792  {
793  const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
794 
795  if(SDRTEXTHORZADJUST_CENTER == eHAdj)
796  {
797  aAdjustTranslate.setX(fFree / 2.0);
798  }
799 
800  if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
801  {
802  aAdjustTranslate.setX(fFree);
803  }
804  }
805 
806  // correct vertical translation using the now known text size
807  if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
808  {
809  const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
810 
811  if(SDRTEXTVERTADJUST_CENTER == eVAdj)
812  {
813  aAdjustTranslate.setY(fFree / 2.0);
814  }
815 
816  if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
817  {
818  aAdjustTranslate.setY(fFree);
819  }
820  }
821 
822  // prepare matrices to apply to newly created primitives. aNewTransformA
823  // will get coordinates in aOutlinerScale size and positive in X, Y.
824  basegfx::B2DHomMatrix aNewTransformA;
825  basegfx::B2DHomMatrix aNewTransformB;
826 
827  // translate relative to given primitive to get same rotation and shear
828  // as the master shape we are working on. For vertical, use the top-right
829  // corner
830  const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
831  const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
832  aNewTransformA.translate(fStartInX, fStartInY);
833 
834  // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
835  // move the null point which was top left to bottom right.
836  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
837  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
838  aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
839 
840  // in-between the translations of the single primitives will take place. Afterwards,
841  // the object's transformations need to be applied
842  aNewTransformB.shearX(fShearX);
843  aNewTransformB.rotate(fRotate);
844  aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
845 
846  basegfx::B2DRange aClipRange;
847 
848  // now break up text primitives.
849  impTextBreakupHandler aConverter(rOutliner);
850  aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
851 
852  // cleanup outliner
853  rOutliner.Clear();
854  rOutliner.setVisualizedPage(nullptr);
855  rOutliner.SetControlWord(nOriginalControlWord);
856 
857  rTarget = aConverter.getPrimitive2DSequence();
858 }
859 
860 // Resolves: fdo#35779 set background color of this shape as the editeng background if there
861 // is one. Check the shape itself, then the host page, then that page's master page.
863 {
864  const SfxItemSet* pBackgroundFillSet = &GetObjectItemSet();
865 
866  if (drawing::FillStyle_NONE == pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
867  {
868  SdrPage* pOwnerPage(getSdrPageFromSdrObject());
869  if (pOwnerPage)
870  {
871  pBackgroundFillSet = &pOwnerPage->getSdrPageProperties().GetItemSet();
872 
873  if (drawing::FillStyle_NONE == pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
874  {
875  if (!pOwnerPage->IsMasterPage() && pOwnerPage->TRG_HasMasterPage())
876  {
877  pBackgroundFillSet = &pOwnerPage->TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
878  }
879  }
880  }
881  }
882 
883  if (drawing::FillStyle_NONE != pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
884  {
885  Color aColor(rOutliner.GetBackgroundColor());
886  GetDraftFillColor(*pBackgroundFillSet, aColor);
887  rOutliner.SetBackgroundColor(aColor);
888  }
889 }
890 
893  const drawinglayer::primitive2d::SdrBlockTextPrimitive2D& rSdrBlockTextPrimitive,
894  const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
895 {
896  // decompose matrix to have position and size of text
897  basegfx::B2DVector aScale, aTranslate;
898  double fRotate, fShearX;
899  rSdrBlockTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
900 
901  // use B2DRange aAnchorTextRange for calculations
902  basegfx::B2DRange aAnchorTextRange(aTranslate);
903  aAnchorTextRange.expand(aTranslate + aScale);
904 
905  // prepare outliner
906  const bool bIsCell(rSdrBlockTextPrimitive.getCellText());
907  SolarMutexGuard aSolarGuard;
908  SdrOutliner& rOutliner = ImpGetDrawOutliner();
909  SdrTextHorzAdjust eHAdj = rSdrBlockTextPrimitive.getSdrTextHorzAdjust();
910  SdrTextVertAdjust eVAdj = rSdrBlockTextPrimitive.getSdrTextVertAdjust();
911  const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
912  const Size aNullSize;
913 
914  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
915  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
916  rOutliner.SetFixedCellHeight(rSdrBlockTextPrimitive.isFixedCellHeight());
917  rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE);
918  rOutliner.SetMinAutoPaperSize(aNullSize);
919  rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
920 
921  // That color needs to be restored on leaving this method
922  Color aOriginalBackColor(rOutliner.GetBackgroundColor());
923  setSuitableOutlinerBg(rOutliner);
924 
925  // add one to rage sizes to get back to the old Rectangle and outliner measurements
926  const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
927  const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
928  const bool bVerticalWriting(rSdrBlockTextPrimitive.getOutlinerParaObject().IsVertical());
929  const bool bTopToBottom(rSdrBlockTextPrimitive.getOutlinerParaObject().IsTopToBottom());
930  const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
931 
932  if(bIsCell)
933  {
934  // cell text is formatted neither like a text object nor like an object
935  // text, so use a special setup here
936  rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
937 
938  // #i106214# To work with an unchangeable PaperSize (CellSize in
939  // this case) Set(Min|Max)AutoPaperSize and SetPaperSize have to be used.
940  // #i106214# This was not completely correct; to still measure the real
941  // text height to allow vertical adjust (and vice versa for VerticalWritintg)
942  // only one aspect has to be set, but the other one to zero
943  if(bVerticalWriting)
944  {
945  // measure the horizontal text size
946  rOutliner.SetMinAutoPaperSize(Size(0, aAnchorTextSize.Height()));
947  }
948  else
949  {
950  // measure the vertical text size
951  rOutliner.SetMinAutoPaperSize(Size(aAnchorTextSize.Width(), 0));
952  }
953 
954  rOutliner.SetPaperSize(aAnchorTextSize);
955  rOutliner.SetUpdateMode(true);
956  rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
957  }
958  else
959  {
960  // check if block text is used (only one of them can be true)
961  const bool bHorizontalIsBlock(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting);
962  const bool bVerticalIsBlock(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting);
963 
964  // set minimal paper size horizontally/vertically if needed
965  if(bHorizontalIsBlock)
966  {
967  rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
968  }
969  else if(bVerticalIsBlock)
970  {
971  rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
972  }
973 
974  if((rSdrBlockTextPrimitive.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive.getUnlimitedPage())
975  {
976  // #i103454# maximal paper size hor/ver needs to be limited to text
977  // frame size. If it's block text, still allow the 'other' direction
978  // to grow to get a correct real text size when using GetPaperSize().
979  // When just using aAnchorTextSize as maximum, GetPaperSize()
980  // would just return aAnchorTextSize again: this means, the wanted
981  // 'measurement' of the real size of block text would not work
982  Size aMaxAutoPaperSize(aAnchorTextSize);
983 
984  // Usual processing - always grow in one of directions
985  bool bAllowGrowVertical = !bVerticalWriting;
986  bool bAllowGrowHorizontal = bVerticalWriting;
987 
988  // Compatibility mode for tdf#99729
989  if (getSdrModelFromSdrObject().IsAnchoredTextOverflowLegacy())
990  {
991  bAllowGrowVertical = bHorizontalIsBlock;
992  bAllowGrowHorizontal = bVerticalIsBlock;
993  }
994 
995  if (bAllowGrowVertical)
996  {
997  // allow to grow vertical for horizontal texts
998  aMaxAutoPaperSize.setHeight(1000000);
999  }
1000  else if (bAllowGrowHorizontal)
1001  {
1002  // allow to grow horizontal for vertical texts
1003  aMaxAutoPaperSize.setWidth(1000000);
1004  }
1005 
1006  rOutliner.SetMaxAutoPaperSize(aMaxAutoPaperSize);
1007  }
1008 
1009  rOutliner.SetPaperSize(aNullSize);
1010  rOutliner.SetUpdateMode(true);
1011  rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
1012  }
1013 
1014  rOutliner.SetControlWord(nOriginalControlWord);
1015 
1016  // now get back the layouted text size from outliner
1017  const Size aOutlinerTextSize(rOutliner.GetPaperSize());
1018  const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
1019  basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
1020 
1021  // For draw objects containing text correct hor/ver alignment if text is bigger
1022  // than the object itself. Without that correction, the text would always be
1023  // formatted to the left edge (or top edge when vertical) of the draw object.
1024  if(!IsTextFrame() && !bIsCell)
1025  {
1026  if(aAnchorTextRange.getWidth() < aOutlinerScale.getX() && !bVerticalWriting)
1027  {
1028  // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
1029  // else the alignment is wanted.
1030  if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
1031  {
1032  SvxAdjust eAdjust = GetObjectItemSet().Get(EE_PARA_JUST).GetAdjust();
1033  switch(eAdjust)
1034  {
1035  case SvxAdjust::Left: eHAdj = SDRTEXTHORZADJUST_LEFT; break;
1036  case SvxAdjust::Right: eHAdj = SDRTEXTHORZADJUST_RIGHT; break;
1037  case SvxAdjust::Center: eHAdj = SDRTEXTHORZADJUST_CENTER; break;
1038  default: break;
1039  }
1040  }
1041  }
1042 
1043  if(aAnchorTextRange.getHeight() < aOutlinerScale.getY() && bVerticalWriting)
1044  {
1045  // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
1046  // else the alignment is wanted.
1047  if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
1048  {
1049  eVAdj = SDRTEXTVERTADJUST_CENTER;
1050  }
1051  }
1052  }
1053 
1054  // correct horizontal translation using the now known text size
1055  if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
1056  {
1057  const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
1058 
1059  if(SDRTEXTHORZADJUST_CENTER == eHAdj)
1060  {
1061  aAdjustTranslate.setX(fFree / 2.0);
1062  }
1063 
1064  if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
1065  {
1066  aAdjustTranslate.setX(fFree);
1067  }
1068  }
1069 
1070  // correct vertical translation using the now known text size
1071  if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
1072  {
1073  const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
1074 
1075  if(SDRTEXTVERTADJUST_CENTER == eVAdj)
1076  {
1077  aAdjustTranslate.setY(fFree / 2.0);
1078  }
1079 
1080  if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
1081  {
1082  aAdjustTranslate.setY(fFree);
1083  }
1084  }
1085 
1086  // prepare matrices to apply to newly created primitives. aNewTransformA
1087  // will get coordinates in aOutlinerScale size and positive in X, Y.
1088  // Translate relative to given primitive to get same rotation and shear
1089  // as the master shape we are working on. For vertical, use the top-right
1090  // corner
1091  const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
1092  const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
1093  const basegfx::B2DTuple aAdjOffset(fStartInX, fStartInY);
1094  basegfx::B2DHomMatrix aNewTransformA(basegfx::utils::createTranslateB2DHomMatrix(aAdjOffset.getX(), aAdjOffset.getY()));
1095 
1096  // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
1097  // move the null point which was top left to bottom right.
1098  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
1099  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
1100 
1101  // in-between the translations of the single primitives will take place. Afterwards,
1102  // the object's transformations need to be applied
1104  bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
1105  fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
1106 
1107  // create ClipRange (if needed)
1108  basegfx::B2DRange aClipRange;
1109 
1110  // now break up text primitives.
1111  impTextBreakupHandler aConverter(rOutliner);
1112  aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
1113 
1114  // cleanup outliner
1115  rOutliner.SetBackgroundColor(aOriginalBackColor);
1116  rOutliner.Clear();
1117  rOutliner.setVisualizedPage(nullptr);
1118 
1119  rTarget = aConverter.getPrimitive2DSequence();
1120 }
1121 
1124  const drawinglayer::primitive2d::SdrStretchTextPrimitive2D& rSdrStretchTextPrimitive,
1125  const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
1126 {
1127  // decompose matrix to have position and size of text
1128  basegfx::B2DVector aScale, aTranslate;
1129  double fRotate, fShearX;
1130  rSdrStretchTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
1131 
1132  // prepare outliner
1133  SolarMutexGuard aSolarGuard;
1134  SdrOutliner& rOutliner = ImpGetDrawOutliner();
1135  const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
1136  const Size aNullSize;
1137 
1138  rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE);
1139  rOutliner.SetFixedCellHeight(rSdrStretchTextPrimitive.isFixedCellHeight());
1140  rOutliner.SetMinAutoPaperSize(aNullSize);
1141  rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
1142  rOutliner.SetPaperSize(aNullSize);
1143  rOutliner.SetUpdateMode(true);
1144  rOutliner.SetText(rSdrStretchTextPrimitive.getOutlinerParaObject());
1145 
1146  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1147  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
1148 
1149  // now get back the laid out text size from outliner
1150  const Size aOutlinerTextSize(rOutliner.CalcTextSize());
1151  const basegfx::B2DVector aOutlinerScale(
1152  basegfx::fTools::equalZero(aOutlinerTextSize.Width()) ? 1.0 : aOutlinerTextSize.Width(),
1153  basegfx::fTools::equalZero(aOutlinerTextSize.Height()) ? 1.0 : aOutlinerTextSize.Height());
1154 
1155  // prepare matrices to apply to newly created primitives
1156  basegfx::B2DHomMatrix aNewTransformA;
1157 
1158  // #i101957# Check for vertical text. If used, aNewTransformA
1159  // needs to translate the text initially around object width to orient
1160  // it relative to the topper right instead of the topper left
1161  const bool bVertical(rSdrStretchTextPrimitive.getOutlinerParaObject().IsVertical());
1162  const bool bTopToBottom(rSdrStretchTextPrimitive.getOutlinerParaObject().IsTopToBottom());
1163 
1164  if(bVertical)
1165  {
1166  if(bTopToBottom)
1167  aNewTransformA.translate(aScale.getX(), 0.0);
1168  else
1169  aNewTransformA.translate(0.0, aScale.getY());
1170  }
1171 
1172  // calculate global char stretching scale parameters. Use non-mirrored sizes
1173  // to layout without mirroring
1174  const double fScaleX(fabs(aScale.getX()) / aOutlinerScale.getX());
1175  const double fScaleY(fabs(aScale.getY()) / aOutlinerScale.getY());
1176  rOutliner.SetGlobalCharStretching(static_cast<sal_Int16>(FRound(fScaleX * 100.0)), static_cast<sal_Int16>(FRound(fScaleY * 100.0)));
1177 
1178  // When mirroring in X and Y,
1179  // move the null point which was top left to bottom right.
1180  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
1181  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
1182 
1183  // in-between the translations of the single primitives will take place. Afterwards,
1184  // the object's transformations need to be applied
1186  bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
1187  fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
1188 
1189  // now break up text primitives.
1190  impTextBreakupHandler aConverter(rOutliner);
1191  aConverter.decomposeStretchTextPrimitive(aNewTransformA, aNewTransformB);
1192 
1193  // cleanup outliner
1194  rOutliner.SetControlWord(nOriginalControlWord);
1195  rOutliner.Clear();
1196  rOutliner.setVisualizedPage(nullptr);
1197 
1198  rTarget = aConverter.getPrimitive2DSequence();
1199 }
1200 
1201 
1202 // timing generators
1203 #define ENDLESS_LOOP (0xffffffff)
1204 #define ENDLESS_TIME (double(0xffffffff))
1205 #define PIXEL_DPI (96.0)
1206 
1208 {
1209  if(SdrTextAniKind::Blink != GetTextAniKind())
1210  return;
1211 
1212  // get values
1213  const SfxItemSet& rSet = GetObjectItemSet();
1214  const sal_uInt32 nRepeat(static_cast<sal_uInt32>(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue()));
1215  double fDelay(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIDELAY).GetValue()));
1216 
1217  if(0.0 == fDelay)
1218  {
1219  // use default
1220  fDelay = 250.0;
1221  }
1222 
1223  // prepare loop and add
1224  drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
1226  aLoop.append(aStart);
1228  aLoop.append(aEnd);
1229  rAnimList.append(aLoop);
1230 
1231  // add stopped state if loop is not endless
1232  if(0 != nRepeat)
1233  {
1234  bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
1235  drawinglayer::animation::AnimationEntryFixed aStop(ENDLESS_TIME, bVisibleWhenStopped ? 0.0 : 1.0);
1236  rAnimList.append(aStop);
1237  }
1238 }
1239 
1240 static void impCreateScrollTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
1241 {
1242  bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
1243  bool bVisibleWhenStarted(rSet.Get(SDRATTR_TEXT_ANISTARTINSIDE).GetValue());
1244  const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
1245 
1246  if(bVisibleWhenStarted)
1247  {
1248  // move from center to outside
1249  drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
1250  rAnimList.append(aInOut);
1251  }
1252 
1253  // loop. In loop, move through
1254  drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
1255  drawinglayer::animation::AnimationEntryLinear aThrough(fTimeFullPath, fFrequency, bForward ? 0.0 : 1.0, bForward ? 1.0 : 0.0);
1256  aLoop.append(aThrough);
1257  rAnimList.append(aLoop);
1258 
1259  if(0 != nRepeat && bVisibleWhenStopped)
1260  {
1261  // move from outside to center
1262  drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
1263  rAnimList.append(aOutIn);
1264 
1265  // add timing for staying at the end
1267  rAnimList.append(aEnd);
1268  }
1269 }
1270 
1271 static void impCreateAlternateTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, double fRelativeTextLength, bool bForward, double fTimeFullPath, double fFrequency)
1272 {
1273  if(basegfx::fTools::more(fRelativeTextLength, 0.5))
1274  {
1275  // this is the case when fTextLength > fFrameLength, text is bigger than animation frame.
1276  // In that case, correct direction
1277  bForward = !bForward;
1278  }
1279 
1280  const double fStartPosition(bForward ? fRelativeTextLength : 1.0 - fRelativeTextLength);
1281  const double fEndPosition(bForward ? 1.0 - fRelativeTextLength : fRelativeTextLength);
1282  bool bVisibleWhenStarted(rSet.Get(SDRATTR_TEXT_ANISTARTINSIDE).GetValue());
1283  const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
1284 
1285  if(!bVisibleWhenStarted)
1286  {
1287  // move from outside to center
1288  drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
1289  rAnimList.append(aOutIn);
1290  }
1291 
1292  // loop. In loop, move out and in again. fInnerMovePath may be negative when text is bigger then frame,
1293  // so use absolute value
1294  const double fInnerMovePath(fabs(1.0 - (fRelativeTextLength * 2.0)));
1295  const double fTimeForInnerPath(fTimeFullPath * fInnerMovePath);
1296  const double fHalfInnerPath(fTimeForInnerPath * 0.5);
1297  const sal_uInt32 nDoubleRepeat(nRepeat / 2L);
1298 
1299  if(nDoubleRepeat || 0 == nRepeat)
1300  {
1301  // double forth and back loop
1302  drawinglayer::animation::AnimationEntryLoop aLoop(nDoubleRepeat ? nDoubleRepeat : ENDLESS_LOOP);
1303  drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
1304  aLoop.append(aTime0);
1305  drawinglayer::animation::AnimationEntryLinear aTime1(fTimeForInnerPath, fFrequency, fEndPosition, fStartPosition);
1306  aLoop.append(aTime1);
1307  drawinglayer::animation::AnimationEntryLinear aTime2(fHalfInnerPath, fFrequency, fStartPosition, 0.5);
1308  aLoop.append(aTime2);
1309  rAnimList.append(aLoop);
1310  }
1311 
1312  if(nRepeat % 2L)
1313  {
1314  // repeat is uneven, so we need one more forth and back to center
1315  drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
1316  rAnimList.append(aTime0);
1317  drawinglayer::animation::AnimationEntryLinear aTime1(fHalfInnerPath, fFrequency, fEndPosition, 0.5);
1318  rAnimList.append(aTime1);
1319  }
1320 
1321  if(0 != nRepeat)
1322  {
1323  bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
1324  if(bVisibleWhenStopped)
1325  {
1326  // add timing for staying at the end
1328  rAnimList.append(aEnd);
1329  }
1330  else
1331  {
1332  // move from center to outside
1333  drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
1334  rAnimList.append(aInOut);
1335  }
1336  }
1337 }
1338 
1339 static void impCreateSlideTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
1340 {
1341  // move in from outside, start outside
1342  const double fStartPosition(bForward ? 0.0 : 1.0);
1343  const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
1344 
1345  // move from outside to center
1346  drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
1347  rAnimList.append(aOutIn);
1348 
1349  // loop. In loop, move out and in again
1350  if(nRepeat > 1 || 0 == nRepeat)
1351  {
1352  drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat - 1 : ENDLESS_LOOP);
1353  drawinglayer::animation::AnimationEntryLinear aTime0(fTimeFullPath * 0.5, fFrequency, 0.5, fStartPosition);
1354  aLoop.append(aTime0);
1355  drawinglayer::animation::AnimationEntryLinear aTime1(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
1356  aLoop.append(aTime1);
1357  rAnimList.append(aLoop);
1358  }
1359 
1360  // always visible when stopped, so add timing for staying at the end when not endless
1361  if(0 != nRepeat)
1362  {
1364  rAnimList.append(aEnd);
1365  }
1366 }
1367 
1368 void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
1369 {
1370  const SdrTextAniKind eAniKind(GetTextAniKind());
1371 
1372  if(SdrTextAniKind::Scroll != eAniKind && SdrTextAniKind::Alternate != eAniKind && SdrTextAniKind::Slide != eAniKind)
1373  return;
1374 
1375  // get data. Goal is to calculate fTimeFullPath which is the time needed to
1376  // move animation from (0.0) to (1.0) state
1377  const SfxItemSet& rSet = GetObjectItemSet();
1378  double fAnimationDelay(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIDELAY).GetValue()));
1379  double fSingleStepWidth(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIAMOUNT).GetValue()));
1380  const SdrTextAniDirection eDirection(GetTextAniDirection());
1381  const bool bForward(SdrTextAniDirection::Right == eDirection || SdrTextAniDirection::Down == eDirection);
1382 
1383  if(basegfx::fTools::equalZero(fAnimationDelay))
1384  {
1385  // default to 1/20 second
1386  fAnimationDelay = 50.0;
1387  }
1388 
1389  if(basegfx::fTools::less(fSingleStepWidth, 0.0))
1390  {
1391  // data is in pixels, convert to logic. Imply PIXEL_DPI dpi.
1392  // It makes no sense to keep the view-transformation centered
1393  // definitions, so get rid of them here.
1394  fSingleStepWidth = (-fSingleStepWidth * (2540.0 / PIXEL_DPI));
1395  }
1396 
1397  if(basegfx::fTools::equalZero(fSingleStepWidth))
1398  {
1399  // default to 1 millimeter
1400  fSingleStepWidth = 100.0;
1401  }
1402 
1403  // use the length of the full animation path and the number of steps
1404  // to get the full path time
1405  const double fFullPathLength(fFrameLength + fTextLength);
1406  const double fNumberOfSteps(fFullPathLength / fSingleStepWidth);
1407  double fTimeFullPath(fNumberOfSteps * fAnimationDelay);
1408 
1409  if(fTimeFullPath < fAnimationDelay)
1410  {
1411  fTimeFullPath = fAnimationDelay;
1412  }
1413 
1414  switch(eAniKind)
1415  {
1416  case SdrTextAniKind::Scroll :
1417  {
1418  impCreateScrollTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
1419  break;
1420  }
1422  {
1423  double fRelativeTextLength(fTextLength / (fFrameLength + fTextLength));
1424  impCreateAlternateTiming(rSet, rAnimList, fRelativeTextLength, bForward, fTimeFullPath, fAnimationDelay);
1425  break;
1426  }
1427  case SdrTextAniKind::Slide :
1428  {
1429  impCreateSlideTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
1430  break;
1431  }
1432  default : break; // SdrTextAniKind::NONE, SdrTextAniKind::Blink
1433  }
1434 }
1435 
1437 {
1438  if (GetTextChain()->GetNilChainingEvent(this))
1439  return;
1440 
1441  GetTextChain()->SetNilChainingEvent(this, true);
1442 
1443  TextChainFlow aTxtChainFlow(const_cast<SdrTextObj*>(this));
1444  bool bIsOverflow;
1445 
1446 #ifdef DBG_UTIL
1447  // Some debug output
1448  size_t nObjCount(getSdrPageFromSdrObject()->GetObjCount());
1449  for (size_t i = 0; i < nObjCount; i++)
1450  {
1451  SdrTextObj* pCurObj(dynamic_cast< SdrTextObj* >(getSdrPageFromSdrObject()->GetObj(i)));
1452  if(pCurObj == this)
1453  {
1454  SAL_INFO("svx.chaining", "Working on TextBox " << i);
1455  break;
1456  }
1457  }
1458 #endif
1459 
1460  aTxtChainFlow.CheckForFlowEvents(&rOutliner);
1461 
1462  if (aTxtChainFlow.IsUnderflow() && !IsInEditMode())
1463  {
1464  // underflow-induced overflow
1465  aTxtChainFlow.ExecuteUnderflow(&rOutliner);
1466  bIsOverflow = aTxtChainFlow.IsOverflow();
1467  } else {
1468  // standard overflow (no underflow before)
1469  bIsOverflow = aTxtChainFlow.IsOverflow();
1470  }
1471 
1472  if (bIsOverflow && !IsInEditMode()) {
1473  // Initialize Chaining Outliner
1474  SdrOutliner &rChainingOutl(getSdrModelFromSdrObject().GetChainingOutliner(this));
1475  ImpInitDrawOutliner( rChainingOutl );
1476  rChainingOutl.SetUpdateMode(true);
1477  // We must pass the chaining outliner otherwise we would mess up decomposition
1478  aTxtChainFlow.ExecuteOverflow(&rOutliner, &rChainingOutl);
1479  }
1480 
1481  GetTextChain()->SetNilChainingEvent(this, false);
1482 }
1483 
1486  const drawinglayer::primitive2d::SdrChainedTextPrimitive2D& rSdrChainedTextPrimitive,
1487  const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
1488 {
1489  // decompose matrix to have position and size of text
1490  basegfx::B2DVector aScale, aTranslate;
1491  double fRotate, fShearX;
1492  rSdrChainedTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
1493 
1494  // use B2DRange aAnchorTextRange for calculations
1495  basegfx::B2DRange aAnchorTextRange(aTranslate);
1496  aAnchorTextRange.expand(aTranslate + aScale);
1497 
1498  // prepare outliner
1499  const SfxItemSet& rTextItemSet = rSdrChainedTextPrimitive.getSdrText()->GetItemSet();
1500  SolarMutexGuard aSolarGuard;
1501  SdrOutliner& rOutliner = ImpGetDrawOutliner();
1502 
1503  SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
1504  SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
1505  const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
1506  const Size aNullSize;
1507 
1508  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1509  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
1510 
1511  rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
1512  rOutliner.SetMinAutoPaperSize(aNullSize);
1513  rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
1514 
1515  // add one to rage sizes to get back to the old Rectangle and outliner measurements
1516  const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
1517  const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
1518 
1519  // Text
1520  const OutlinerParaObject* pOutlinerParaObject = rSdrChainedTextPrimitive.getSdrText()->GetOutlinerParaObject();
1521  OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
1522 
1523  const bool bVerticalWriting(pOutlinerParaObject->IsVertical());
1524  const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
1525  const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
1526 
1527  if(IsTextFrame())
1528  {
1529  rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
1530  }
1531 
1532  if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting)
1533  {
1534  rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
1535  }
1536 
1537  if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting)
1538  {
1539  rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
1540  }
1541 
1542  rOutliner.SetPaperSize(aNullSize);
1543  rOutliner.SetUpdateMode(true);
1544  // Sets original text
1545  rOutliner.SetText(*pOutlinerParaObject);
1546 
1547  /* Begin overflow/underflow handling */
1548 
1549  impHandleChainingEventsDuringDecomposition(rOutliner);
1550 
1551  /* End overflow/underflow handling */
1552 
1553  // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1554  rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
1555 
1556  // now get back the layouted text size from outliner
1557  const Size aOutlinerTextSize(rOutliner.GetPaperSize());
1558  const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
1559  basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
1560 
1561  // correct horizontal translation using the now known text size
1562  if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
1563  {
1564  const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
1565 
1566  if(SDRTEXTHORZADJUST_CENTER == eHAdj)
1567  {
1568  aAdjustTranslate.setX(fFree / 2.0);
1569  }
1570 
1571  if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
1572  {
1573  aAdjustTranslate.setX(fFree);
1574  }
1575  }
1576 
1577  // correct vertical translation using the now known text size
1578  if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
1579  {
1580  const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
1581 
1582  if(SDRTEXTVERTADJUST_CENTER == eVAdj)
1583  {
1584  aAdjustTranslate.setY(fFree / 2.0);
1585  }
1586 
1587  if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
1588  {
1589  aAdjustTranslate.setY(fFree);
1590  }
1591  }
1592 
1593  // prepare matrices to apply to newly created primitives. aNewTransformA
1594  // will get coordinates in aOutlinerScale size and positive in X, Y.
1595  basegfx::B2DHomMatrix aNewTransformA;
1596  basegfx::B2DHomMatrix aNewTransformB;
1597 
1598  // translate relative to given primitive to get same rotation and shear
1599  // as the master shape we are working on. For vertical, use the top-right
1600  // corner
1601  const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
1602  const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
1603  aNewTransformA.translate(fStartInX, fStartInY);
1604 
1605  // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
1606  // move the null point which was top left to bottom right.
1607  const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
1608  const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
1609  aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
1610 
1611  // in-between the translations of the single primitives will take place. Afterwards,
1612  // the object's transformations need to be applied
1613  aNewTransformB.shearX(fShearX);
1614  aNewTransformB.rotate(fRotate);
1615  aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
1616 
1617  basegfx::B2DRange aClipRange;
1618 
1619  // now break up text primitives.
1620  impTextBreakupHandler aConverter(rOutliner);
1621  aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
1622 
1623  // cleanup outliner
1624  rOutliner.Clear();
1625  rOutliner.setVisualizedPage(nullptr);
1626  rOutliner.SetControlWord(nOriginalControlWord);
1627 
1628  rTarget = aConverter.getPrimitive2DSequence();
1629 }
1630 
1631 // Direct decomposer for text visualization when you already have a prepared
1632 // Outliner containing all the needed information
1635  SdrOutliner& rOutliner,
1636  const basegfx::B2DHomMatrix& rNewTransformA,
1637  const basegfx::B2DHomMatrix& rNewTransformB,
1638  const basegfx::B2DRange& rClipRange)
1639 {
1640  impTextBreakupHandler aConverter(rOutliner);
1641  aConverter.decomposeBlockTextPrimitive(rNewTransformA, rNewTransformB, rClipRange);
1642  rTarget.append(aConverter.getPrimitive2DSequence());
1643 }
1644 
1645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SdrPage & TRG_GetMasterPage() const
Definition: svdpage.cxx:1567
bool IsOverflow() const
const long * mpDXArray
void impDecomposeContourTextPrimitive(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const drawinglayer::primitive2d::SdrContourTextPrimitive2D &rSdrContourTextPrimitive, const drawinglayer::geometry::ViewInformation2D &aViewInformation) const
void expand(const B2DTuple &rTuple)
constexpr TypedWhichId< SdrTextAniStartInsideItem > SDRATTR_TEXT_ANISTARTINSIDE(SDRATTR_MISC_FIRST+16)
void setVisualizedPage(const SdrPage *pPage)
Definition: svdoutl.hxx:43
sal_uInt8 GetPropr() const
const SfxItemSet & GetItemSet() const
Definition: svdtext.cxx:67
static void impDecomposeBlockTextPrimitiveDirect(drawinglayer::primitive2d::Primitive2DContainer &rTarget, SdrOutliner &rOutliner, const basegfx::B2DHomMatrix &rNewTransformA, const basegfx::B2DHomMatrix &rNewTransformB, const basegfx::B2DRange &rClipRange)
const css::lang::Locale * mpLocale
double getHeight() const
long FRound(double fVal)
const basegfx::B2DHomMatrix & getTextRangeTransform() const
const OutlinerParaObject & getOutlinerParaObject() const
IMPL_LINK(MaskData, PipetteHdl, const OString &, rId, void)
Definition: _bmpmask.cxx:192
const OUString maText
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
static bool more(const double &rfValA, const double &rfValB)
static bool equal(const double &rfValA, const double &rfValB)
signed char sal_Int8
#define ENDLESS_TIME
SdrPage * GetSdrPageFromXDrawPage(const uno::Reference< drawing::XDrawPage > &xDrawPage)
returns the SdrObject from the given StarOffice API wrapper
Definition: unopage.cxx:888
void impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList &rAnimList, double fFrameLength, double fTextLength) const
void SetPaperSize(const Size &rSize)
bool IsVertical() const
SdrTextHorzAdjust
Definition: sdtaitm.hxx:53
void SetBackgroundColor(const Color &rColor)
#define F_PI1800
constexpr TypedWhichId< XFillStyleItem > XATTR_FILLSTYLE(XATTR_FILL_FIRST)
double getX() const
double getY() const
sal_Int32 GetParagraphCount() const
void ExecuteUnderflow(SdrOutliner *)
void append(const AnimationEntry &rCandidate)
constexpr TypedWhichId< SvxAdjustItem > EE_PARA_JUST(EE_PARA_START+15)
bool IsTopToBottom() const
constexpr TypedWhichId< SdrTextAniCountItem > SDRATTR_TEXT_ANICOUNT(SDRATTR_MISC_FIRST+18)
const SvxFieldData * mpFieldData
EEControlBits
const OUString & GetTargetFrame() const
attribute::FontAttribute getFontAttributeFromVclFont(basegfx::B2DVector &o_rSize, const vcl::Font &rFont, bool bRTL, bool bBiDiStrong)
void impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList &rAnimList) const
SdrTextAniKind
Animation type for text frame.
Definition: sdtakitm.hxx:29
const SvxFont & mrFont
double getWidth() const
void SetControlWord(EEControlBits nWord)
LINESTYLE_NONE
bool isInside(const B2DTuple &rTuple) const
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
const basegfx::B2DPolyPolygon & getUnitPolyPolygon() const
void impDecomposeBlockTextPrimitive(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const drawinglayer::primitive2d::SdrBlockTextPrimitive2D &rSdrBlockTextPrimitive, const drawinglayer::geometry::ViewInformation2D &aViewInformation) const
void SetFixedCellHeight(bool bUseFixedCellHeight)
bool IsUnderflow() const
const css::uno::Reference< css::drawing::XDrawPage > & getVisualizedPage() const
EEControlBits GetControlWord() const
basegfx::B2DRange getTextBoundRect(const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength) const
static bool less(const double &rfValA, const double &rfValB)
void shearX(double fSx)
void impDecomposeChainedTextPrimitive(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const drawinglayer::primitive2d::SdrChainedTextPrimitive2D &rSdrChainedTextPrimitive, const drawinglayer::geometry::ViewInformation2D &aViewInformation) const
bool isEmpty() const
void impDecomposeStretchTextPrimitive(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const drawinglayer::primitive2d::SdrStretchTextPrimitive2D &rSdrStretchTextPrimitive, const drawinglayer::geometry::ViewInformation2D &aViewInformation) const
const Point & mrStartPos
void impHandleChainingEventsDuringDecomposition(SdrOutliner &rOutliner) const
void SetText(const OutlinerParaObject &)
SvxAdjust
const Color maTextLineColor
int i
uno_Any a
EBulletInfo GetBulletInfo(sal_Int32 nPara)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
void SetGlobalCharStretching(sal_uInt16 nX=100, sal_uInt16 nY=100)
void rotate(double fRadiant)
void ExecuteOverflow(SdrOutliner *, SdrOutliner *)
void SetDrawBulletHdl(const Link< DrawBulletInfo *, void > &rLink)
static bool equalZero(const double &rfVal)
void scale(double fX, double fY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
virtual void append(const Primitive2DReference &) override
const Color maOverlineColor
bool IsMasterPage() const
Definition: svdpage.hxx:451
const OUString & GetRepresentation() const
const SfxItemSet & GetItemSet() const
Definition: svdpage.hxx:335
TextStrikeout mapFontStrikeoutToTextStrikeout(FontStrikeout eFontStrikeout)
sal_Int32 mnPara
SdrPageProperties & getSdrPageProperties()
Definition: svdpage.cxx:1766
bool TRG_HasMasterPage() const
Definition: svdpage.hxx:485
sal_Int16 GetDepth(sal_Int32 nPara) const
void StripPortions()
bool IsRTL() const
void SetDrawPortionHdl(const Link< DrawPortionInfo *, void > &rLink)
const OUString & GetURL() const
const basegfx::B2DHomMatrix & getObjectTransform() const
void SetPolygon(const basegfx::B2DPolyPolygon &rPolyPolygon)
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
void SetMaxAutoPaperSize(const Size &rSz)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
TextLine mapFontLineStyleToTextLine(FontLineStyle eLineStyle)
void impDecomposeAutoFitTextPrimitive(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const drawinglayer::primitive2d::SdrAutoFitTextPrimitive2D &rSdrAutofitTextPrimitive, const drawinglayer::geometry::ViewInformation2D &aViewInformation) const
const basegfx::B2DHomMatrix & getTextRangeTransform() const
#define SAL_INFO(area, stream)
const basegfx::B2DHomMatrix & getTextRangeTransform() const
constexpr TypedWhichId< SdrTextAniStopInsideItem > SDRATTR_TEXT_ANISTOPINSIDE(SDRATTR_MISC_FIRST+17)
void SetMinAutoPaperSize(const Size &rSz)
#define ENDLESS_LOOP
#define DFLT_ESC_SUPER
Point maBulletPosition
OUString CalcCaseMap(const OUString &rTxt) const
short GetEscapement() const
void SetUpdateMode(bool bUpdate)
void translate(double fX, double fY)
SdrTextAniDirection
Definition: sdtaditm.hxx:29
const EEngineData::WrongSpellVector * mpWrongSpellVector
void setSuitableOutlinerBg(Outliner &rOutliner) const
sal_Int32 mnTextStart
static void impCreateScrollTiming(const SfxItemSet &rSet, drawinglayer::animation::AnimationEntryList &rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
#define PIXEL_DPI
const basegfx::B2DHomMatrix & getTextRangeTransform() const
constexpr TypedWhichId< SdrTextAniDelayItem > SDRATTR_TEXT_ANIDELAY(SDRATTR_MISC_FIRST+19)
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:366
#define MAX_ESC_POS
long getHeight() const
void Clear()
OutlinerParaObject * GetOutlinerParaObject() const
Definition: svdtext.cxx:88
STRIKEOUT_NONE
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
bool GetDraftFillColor(const SfxItemSet &rSet, Color &rCol)
Returns a replacement for an XFillStyle.
Definition: svdetc.cxx:236
sal_Int32 mnTextLen
long getWidth() const
static void impCreateAlternateTiming(const SfxItemSet &rSet, drawinglayer::animation::AnimationEntryList &rAnimList, double fRelativeTextLength, bool bForward, double fTimeFullPath, double fFrequency)
void setWidth(long nWidth)
const GraphicObject maBulletGraphicObject
Size CalcTextSize()
static void impCreateSlideTiming(const SfxItemSet &rSet, drawinglayer::animation::AnimationEntryList &rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
void setFont(const vcl::Font &rFont)
SdrTextVertAdjust
Definition: sdtaitm.hxx:29
scroll back and forth
constexpr TypedWhichId< SdrTextAniAmountItem > SDRATTR_TEXT_ANIAMOUNT(SDRATTR_MISC_FIRST+20)
Color const & GetBackgroundColor() const
virtual void CheckForFlowEvents(SdrOutliner *)
SvxURLFormat GetFormat() const
void setHeight(long nHeight)
const Size & GetPaperSize() const