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