LCOV - code coverage report
Current view: top level - svx/source/svdraw - svdotextdecomposition.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 276 578 47.8 %
Date: 2015-06-13 12:38:46 Functions: 17 37 45.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <svx/svdetc.hxx>
      22             : #include <svx/svdoutl.hxx>
      23             : #include <svx/svdpage.hxx>
      24             : #include <svx/svdotext.hxx>
      25             : #include <basegfx/vector/b2dvector.hxx>
      26             : #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
      27             : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
      28             : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
      29             : #include <basegfx/range/b2drange.hxx>
      30             : #include <editeng/editstat.hxx>
      31             : #include <tools/helpers.hxx>
      32             : #include <svx/sdtfchim.hxx>
      33             : #include <svl/itemset.hxx>
      34             : #include <basegfx/polygon/b2dpolygontools.hxx>
      35             : #include <basegfx/polygon/b2dpolygon.hxx>
      36             : #include <drawinglayer/animation/animationtiming.hxx>
      37             : #include <basegfx/color/bcolor.hxx>
      38             : #include <vcl/svapp.hxx>
      39             : #include <editeng/eeitemid.hxx>
      40             : #include <editeng/escapementitem.hxx>
      41             : #include <editeng/svxenum.hxx>
      42             : #include <editeng/flditem.hxx>
      43             : #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
      44             : #include <vcl/metaact.hxx>
      45             : #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
      46             : #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
      47             : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
      48             : #include <svx/unoapi.hxx>
      49             : #include <drawinglayer/geometry/viewinformation2d.hxx>
      50             : #include <editeng/outlobj.hxx>
      51             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      52             : 
      53             : using namespace com::sun::star;
      54             : 
      55             : // helpers
      56             : 
      57             : namespace
      58             : {
      59       59236 :     drawinglayer::primitive2d::Primitive2DSequence impConvertVectorToPrimitive2DSequence(const std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rPrimitiveVector)
      60             :     {
      61       59236 :         const sal_Int32 nCount(rPrimitiveVector.size());
      62       59236 :         drawinglayer::primitive2d::Primitive2DSequence aRetval(nCount);
      63             : 
      64      123976 :         for(sal_Int32 a(0L); a < nCount; a++)
      65             :         {
      66       64740 :             aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(rPrimitiveVector[a]);
      67             :         }
      68             : 
      69       59236 :         return aRetval;
      70             :     }
      71             : 
      72       17483 :     class impTextBreakupHandler
      73             :     {
      74             :     private:
      75             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maTextPortionPrimitives;
      76             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maLinePrimitives;
      77             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maParagraphPrimitives;
      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* );
      93             :         DECL_LINK(decomposeBlockTextPrimitive, DrawPortionInfo* );
      94             :         DECL_LINK(decomposeStretchTextPrimitive, DrawPortionInfo* );
      95             : 
      96             :         DECL_LINK(decomposeContourBulletPrimitive, DrawBulletInfo* );
      97             :         DECL_LINK(decomposeBlockBulletPrimitive, DrawBulletInfo* );
      98             :         DECL_LINK(decomposeStretchBulletPrimitive, DrawBulletInfo* );
      99             : 
     100             :         static bool impIsUnderlineAbove(const vcl::Font& rFont);
     101             :         void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
     102             :         static drawinglayer::primitive2d::BasePrimitive2D* impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo);
     103             :         void impFlushTextPortionPrimitivesToLinePrimitives();
     104             :         void impFlushLinePrimitivesToParagraphPrimitives();
     105             :         void impHandleDrawPortionInfo(const DrawPortionInfo& rInfo);
     106             :         void impHandleDrawBulletInfo(const DrawBulletInfo& rInfo);
     107             : 
     108             :     public:
     109       17483 :         explicit impTextBreakupHandler(SdrOutliner& rOutliner)
     110             :         :   maTextPortionPrimitives(),
     111             :             maLinePrimitives(),
     112             :             maParagraphPrimitives(),
     113             :             mrOutliner(rOutliner),
     114             :             maNewTransformA(),
     115             :             maNewTransformB(),
     116             :             maScale(),
     117       17483 :             maClipRange()
     118             :         {
     119       17483 :         }
     120             : 
     121           0 :         void decomposeContourTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB, const basegfx::B2DVector& rScale)
     122             :         {
     123           0 :             maScale = rScale;
     124           0 :             maNewTransformA = rNewTransformA;
     125           0 :             maNewTransformB = rNewTransformB;
     126           0 :             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeContourTextPrimitive));
     127           0 :             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeContourBulletPrimitive));
     128           0 :             mrOutliner.StripPortions();
     129           0 :             mrOutliner.SetDrawPortionHdl(Link<>());
     130           0 :             mrOutliner.SetDrawBulletHdl(Link<>());
     131           0 :         }
     132             : 
     133       17483 :         void decomposeBlockTextPrimitive(
     134             :             const basegfx::B2DHomMatrix& rNewTransformA,
     135             :             const basegfx::B2DHomMatrix& rNewTransformB,
     136             :             const basegfx::B2DRange& rClipRange)
     137             :         {
     138       17483 :             maNewTransformA = rNewTransformA;
     139       17483 :             maNewTransformB = rNewTransformB;
     140       17483 :             maClipRange = rClipRange;
     141       17483 :             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeBlockTextPrimitive));
     142       17483 :             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeBlockBulletPrimitive));
     143       17483 :             mrOutliner.StripPortions();
     144       17483 :             mrOutliner.SetDrawPortionHdl(Link<>());
     145       17483 :             mrOutliner.SetDrawBulletHdl(Link<>());
     146       17483 :         }
     147             : 
     148           0 :         void decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB)
     149             :         {
     150           0 :             maNewTransformA = rNewTransformA;
     151           0 :             maNewTransformB = rNewTransformB;
     152           0 :             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeStretchTextPrimitive));
     153           0 :             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeStretchBulletPrimitive));
     154           0 :             mrOutliner.StripPortions();
     155           0 :             mrOutliner.SetDrawPortionHdl(Link<>());
     156           0 :             mrOutliner.SetDrawBulletHdl(Link<>());
     157           0 :         }
     158             : 
     159             :         drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence();
     160             :     };
     161             : 
     162        1862 :     bool impTextBreakupHandler::impIsUnderlineAbove(const vcl::Font& rFont)
     163             :     {
     164        1862 :         if(!rFont.IsVertical())
     165             :         {
     166        1862 :             return false;
     167             :         }
     168             : 
     169           0 :         if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
     170             :         {
     171             :             // the underline is right for Japanese only
     172           0 :             return true;
     173             :         }
     174             : 
     175           0 :         return false;
     176             :     }
     177             : 
     178       23789 :     void impTextBreakupHandler::impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo)
     179             :     {
     180       23789 :         if(!rInfo.maText.isEmpty() && rInfo.mnTextLen)
     181             :         {
     182       22987 :             OUString caseMappedText = rInfo.mrFont.CalcCaseMap( rInfo.maText );
     183       45974 :             basegfx::B2DVector aFontScaling;
     184             :             drawinglayer::attribute::FontAttribute aFontAttribute(
     185             :                 drawinglayer::primitive2d::getFontAttributeFromVclFont(
     186             :                     aFontScaling,
     187             :                     rInfo.mrFont,
     188       22987 :                     rInfo.IsRTL(),
     189       45974 :                     false));
     190       45974 :             basegfx::B2DHomMatrix aNewTransform;
     191             : 
     192             :             // add font scale to new transform
     193       22987 :             aNewTransform.scale(aFontScaling.getX(), aFontScaling.getY());
     194             : 
     195             :             // look for proportional font scaling, if necessary, scale accordingly
     196       22987 :             if(100 != rInfo.mrFont.GetPropr())
     197             :             {
     198           0 :                 const double fFactor(rInfo.mrFont.GetPropr() / 100.0);
     199           0 :                 aNewTransform.scale(fFactor, fFactor);
     200             :             }
     201             : 
     202             :             // apply font rotate
     203       22987 :             if(rInfo.mrFont.GetOrientation())
     204             :             {
     205           2 :                 aNewTransform.rotate(-rInfo.mrFont.GetOrientation() * F_PI1800);
     206             :             }
     207             : 
     208             :             // look for escapement, if necessary, translate accordingly
     209       22987 :             if(rInfo.mrFont.GetEscapement())
     210             :             {
     211        1286 :                 sal_Int16 nEsc(rInfo.mrFont.GetEscapement());
     212             : 
     213        1286 :                 if(DFLT_ESC_AUTO_SUPER == nEsc)
     214             :                 {
     215           0 :                     nEsc = 33;
     216             :                 }
     217        1286 :                 else if(DFLT_ESC_AUTO_SUB == nEsc)
     218             :                 {
     219           0 :                     nEsc = -20;
     220             :                 }
     221             : 
     222        1286 :                 if(nEsc > 100)
     223             :                 {
     224           0 :                     nEsc = 100;
     225             :                 }
     226        1286 :                 else if(nEsc < -100)
     227             :                 {
     228           0 :                     nEsc = -100;
     229             :                 }
     230             : 
     231        1286 :                 const double fEscapement(nEsc / -100.0);
     232        1286 :                 aNewTransform.translate(0.0, fEscapement * aFontScaling.getY());
     233             :             }
     234             : 
     235             :             // apply transformA
     236       22987 :             aNewTransform *= maNewTransformA;
     237             : 
     238             :             // apply local offset
     239       22987 :             aNewTransform.translate(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y());
     240             : 
     241             :             // also apply embedding object's transform
     242       22987 :             aNewTransform *= maNewTransformB;
     243             : 
     244             :             // prepare DXArray content. To make it independent from font size (and such from
     245             :             // the text transformation), scale it to unit coordinates
     246       45974 :             ::std::vector< double > aDXArray;
     247             :             static bool bDisableTextArray(false);
     248             : 
     249       22987 :             if(!bDisableTextArray && rInfo.mpDXArray && rInfo.mnTextLen)
     250             :             {
     251       22987 :                 aDXArray.reserve(rInfo.mnTextLen);
     252             : 
     253      171811 :                 for(sal_Int32 a=0; a < rInfo.mnTextLen; a++)
     254             :                 {
     255      148824 :                     aDXArray.push_back((double)rInfo.mpDXArray[a]);
     256             :                 }
     257             :             }
     258             : 
     259             :             // create complex text primitive and append
     260       22987 :             const Color aFontColor(rInfo.mrFont.GetColor());
     261       45974 :             const basegfx::BColor aBFontColor(aFontColor.getBColor());
     262             : 
     263       22987 :             const Color aTextFillColor(rInfo.mrFont.GetFillColor());
     264             : 
     265             :             // prepare wordLineMode (for underline and strikeout)
     266             :             // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)'
     267             :             // to be split which would not look like the original
     268       22987 :             const bool bWordLineMode(rInfo.mrFont.IsWordLineMode() && !rInfo.mbEndOfBullet);
     269             : 
     270             :             // prepare new primitive
     271       22987 :             drawinglayer::primitive2d::BasePrimitive2D* pNewPrimitive = 0;
     272             :             const bool bDecoratedIsNeeded(
     273       22987 :                    UNDERLINE_NONE != rInfo.mrFont.GetOverline()
     274       21279 :                 || UNDERLINE_NONE != rInfo.mrFont.GetUnderline()
     275       20910 :                 || STRIKEOUT_NONE != rInfo.mrFont.GetStrikeout()
     276       20884 :                 || EMPHASISMARK_NONE != (rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
     277       20884 :                 || RELIEF_NONE != rInfo.mrFont.GetRelief()
     278       20884 :                 || rInfo.mrFont.IsShadow()
     279       43871 :                 || bWordLineMode);
     280             : 
     281       22987 :             if(bDecoratedIsNeeded)
     282             :             {
     283             :                 // TextDecoratedPortionPrimitive2D needed, prepare some more data
     284             :                 // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead
     285        2103 :                 const Color aUnderlineColor(rInfo.maTextLineColor);
     286        2103 :                 const basegfx::BColor aBUnderlineColor((0xffffffff == aUnderlineColor.GetColor()) ? aBFontColor : aUnderlineColor.getBColor());
     287        2103 :                 const Color aOverlineColor(rInfo.maOverlineColor);
     288        4206 :                 const basegfx::BColor aBOverlineColor((0xffffffff == aOverlineColor.GetColor()) ? aBFontColor : aOverlineColor.getBColor());
     289             : 
     290             :                 // prepare overline and underline data
     291             :                 const drawinglayer::primitive2d::TextLine eFontOverline(
     292        2103 :                     drawinglayer::primitive2d::mapFontUnderlineToTextLine(rInfo.mrFont.GetOverline()));
     293             :                 const drawinglayer::primitive2d::TextLine eFontUnderline(
     294        2103 :                     drawinglayer::primitive2d::mapFontUnderlineToTextLine(rInfo.mrFont.GetUnderline()));
     295             : 
     296             :                 // check UnderlineAbove
     297             :                 const bool bUnderlineAbove(
     298        2103 :                     drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && impIsUnderlineAbove(rInfo.mrFont));
     299             : 
     300             :                 // prepare strikeout data
     301             :                 const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(
     302        2103 :                     drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rInfo.mrFont.GetStrikeout()));
     303             : 
     304             :                 // prepare emphasis mark data
     305        2103 :                 drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
     306             : 
     307        2103 :                 switch(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
     308             :                 {
     309         872 :                     case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
     310         576 :                     case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
     311         218 :                     case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
     312         134 :                     case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
     313             :                 }
     314             : 
     315        2103 :                 const bool bEmphasisMarkAbove(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
     316        2103 :                 const bool bEmphasisMarkBelow(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
     317             : 
     318             :                 // prepare font relief data
     319        2103 :                 drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
     320             : 
     321        2103 :                 switch(rInfo.mrFont.GetRelief())
     322             :                 {
     323        1425 :                     case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
     324           0 :                     case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
     325         678 :                     default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
     326             :                 }
     327             : 
     328             :                 // prepare shadow/outline data
     329        2103 :                 const bool bShadow(rInfo.mrFont.IsShadow());
     330             : 
     331             :                 // TextDecoratedPortionPrimitive2D is needed, create one
     332             :                 pNewPrimitive = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
     333             : 
     334             :                     // attributes for TextSimplePortionPrimitive2D
     335             :                     aNewTransform,
     336             :                     caseMappedText,
     337             :                     rInfo.mnTextStart,
     338             :                     rInfo.mnTextLen,
     339             :                     aDXArray,
     340             :                     aFontAttribute,
     341             :                     rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale(),
     342             :                     aBFontColor,
     343             :                     aTextFillColor,
     344             : 
     345             :                     // attributes for TextDecoratedPortionPrimitive2D
     346             :                     aBOverlineColor,
     347             :                     aBUnderlineColor,
     348             :                     eFontOverline,
     349             :                     eFontUnderline,
     350             :                     bUnderlineAbove,
     351             :                     eTextStrikeout,
     352             :                     bWordLineMode,
     353             :                     eTextEmphasisMark,
     354             :                     bEmphasisMarkAbove,
     355             :                     bEmphasisMarkBelow,
     356             :                     eTextRelief,
     357        4206 :                     bShadow);
     358             :             }
     359             :             else
     360             :             {
     361             :                 // TextSimplePortionPrimitive2D is enough
     362             :                 pNewPrimitive = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
     363             :                     aNewTransform,
     364             :                     caseMappedText,
     365             :                     rInfo.mnTextStart,
     366             :                     rInfo.mnTextLen,
     367             :                     aDXArray,
     368             :                     aFontAttribute,
     369             :                     rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale(),
     370             :                     aBFontColor,
     371             :                     rInfo.mbFilled,
     372             :                     rInfo.mnWidthToFill,
     373       20884 :                     aTextFillColor);
     374             :             }
     375             : 
     376       22987 :             if(rInfo.mbEndOfBullet)
     377             :             {
     378             :                 // embed in TextHierarchyBulletPrimitive2D
     379         941 :                 const drawinglayer::primitive2d::Primitive2DReference aNewReference(pNewPrimitive);
     380        1882 :                 const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(&aNewReference, 1);
     381        1882 :                 pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence);
     382             :             }
     383             : 
     384       22987 :             if(rInfo.mpFieldData)
     385             :             {
     386        1603 :                 pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive, rInfo);
     387             :             }
     388             : 
     389       22987 :             maTextPortionPrimitives.push_back(pNewPrimitive);
     390             : 
     391             :             // support for WrongSpellVector. Create WrongSpellPrimitives as needed
     392       22987 :             if(rInfo.mpWrongSpellVector && !aDXArray.empty())
     393             :             {
     394           0 :                 const sal_Int32 nSize(rInfo.mpWrongSpellVector->size());
     395           0 :                 const sal_Int32 nDXCount(aDXArray.size());
     396           0 :                 const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
     397             : 
     398           0 :                 for(sal_Int32 a(0); a < nSize; a++)
     399             :                 {
     400           0 :                     const EEngineData::WrongSpellClass& rCandidate = (*rInfo.mpWrongSpellVector)[a];
     401             : 
     402           0 :                     if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
     403             :                     {
     404           0 :                         const sal_Int32 nStart(rCandidate.nStart - rInfo.mnTextStart);
     405           0 :                         const sal_Int32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
     406           0 :                         double fStart(0.0);
     407           0 :                         double fEnd(0.0);
     408             : 
     409           0 :                         if(nStart > 0 && nStart - 1 < nDXCount)
     410             :                         {
     411           0 :                             fStart = aDXArray[nStart - 1];
     412             :                         }
     413             : 
     414           0 :                         if(nEnd > 0 && nEnd - 1 < nDXCount)
     415             :                         {
     416           0 :                             fEnd = aDXArray[nEnd - 1];
     417             :                         }
     418             : 
     419           0 :                         if(!basegfx::fTools::equal(fStart, fEnd))
     420             :                         {
     421           0 :                             if(rInfo.IsRTL())
     422             :                             {
     423             :                                 // #i98523#
     424             :                                 // When the portion is RTL, mirror the redlining using the
     425             :                                 // full portion width
     426           0 :                                 const double fTextWidth(aDXArray[aDXArray.size() - 1]);
     427             : 
     428           0 :                                 fStart = fTextWidth - fStart;
     429           0 :                                 fEnd = fTextWidth - fEnd;
     430             :                             }
     431             : 
     432             :                             // need to take FontScaling out of values; it's already part of
     433             :                             // aNewTransform and would be double applied
     434           0 :                             const double fFontScaleX(aFontScaling.getX());
     435             : 
     436           0 :                             if(!basegfx::fTools::equal(fFontScaleX, 1.0)
     437           0 :                                 && !basegfx::fTools::equalZero(fFontScaleX))
     438             :                             {
     439           0 :                                 fStart /= fFontScaleX;
     440           0 :                                 fEnd /= fFontScaleX;
     441             :                             }
     442             : 
     443             :                             maTextPortionPrimitives.push_back(new drawinglayer::primitive2d::WrongSpellPrimitive2D(
     444             :                                 aNewTransform,
     445             :                                 fStart,
     446             :                                 fEnd,
     447           0 :                                 aSpellColor));
     448             :                         }
     449             :                     }
     450           0 :                 }
     451       22987 :             }
     452             :         }
     453       23789 :     }
     454             : 
     455        1603 :     drawinglayer::primitive2d::BasePrimitive2D* impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo)
     456             :     {
     457        1603 :         if(rInfo.mpFieldData)
     458             :         {
     459             :             // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D
     460             :             // which holds the field type and, if applicable, the URL
     461        1603 :             const SvxURLField* pURLField = dynamic_cast< const SvxURLField* >(rInfo.mpFieldData);
     462        1603 :             const SvxPageField* pPageField = dynamic_cast< const SvxPageField* >(rInfo.mpFieldData);
     463             : 
     464             :             // embed current primitive to a sequence
     465        1603 :             drawinglayer::primitive2d::Primitive2DSequence aSequence;
     466             : 
     467        1603 :             if(pPrimitive)
     468             :             {
     469        1603 :                 aSequence.realloc(1);
     470        1603 :                 aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive);
     471             :             }
     472             : 
     473        1603 :             if(pURLField)
     474             :             {
     475           1 :                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, pURLField->GetURL());
     476             :             }
     477        1602 :             else if(pPageField)
     478             :             {
     479         404 :                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE, "");
     480             :             }
     481             :             else
     482             :             {
     483        1198 :                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON, "");
     484        1603 :             }
     485             :         }
     486             : 
     487        1603 :         return pPrimitive;
     488             :     }
     489             : 
     490       22719 :     void impTextBreakupHandler::impFlushTextPortionPrimitivesToLinePrimitives()
     491             :     {
     492             :         // only create a line primitive when we had content; there is no need for
     493             :         // empty line primitives (contrary to paragraphs, see below).
     494       22719 :         if(!maTextPortionPrimitives.empty())
     495             :         {
     496       21926 :             drawinglayer::primitive2d::Primitive2DSequence aLineSequence(impConvertVectorToPrimitive2DSequence(maTextPortionPrimitives));
     497       21926 :             maTextPortionPrimitives.clear();
     498       21926 :             maLinePrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyLinePrimitive2D(aLineSequence));
     499             :         }
     500       22719 :     }
     501             : 
     502       19827 :     void impTextBreakupHandler::impFlushLinePrimitivesToParagraphPrimitives()
     503             :     {
     504             :         // ALWAYS create a paragraph primitive, even when no content was added. This is done to
     505             :         // have the correct paragraph count even with empty paragraphs. Those paragraphs will
     506             :         // have an empty sub-PrimitiveSequence.
     507       19827 :         drawinglayer::primitive2d::Primitive2DSequence aParagraphSequence(impConvertVectorToPrimitive2DSequence(maLinePrimitives));
     508       19827 :         maLinePrimitives.clear();
     509       19827 :         maParagraphPrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyParagraphPrimitive2D(aParagraphSequence));
     510       19827 :     }
     511             : 
     512       23789 :     void impTextBreakupHandler::impHandleDrawPortionInfo(const DrawPortionInfo& rInfo)
     513             :     {
     514       23789 :         impCreateTextPortionPrimitive(rInfo);
     515             : 
     516       23789 :         if(rInfo.mbEndOfLine || rInfo.mbEndOfParagraph)
     517             :         {
     518       22719 :             impFlushTextPortionPrimitivesToLinePrimitives();
     519             :         }
     520             : 
     521       23789 :         if(rInfo.mbEndOfParagraph)
     522             :         {
     523       19827 :             impFlushLinePrimitivesToParagraphPrimitives();
     524             :         }
     525       23789 :     }
     526             : 
     527           0 :     void impTextBreakupHandler::impHandleDrawBulletInfo(const DrawBulletInfo& rInfo)
     528             :     {
     529           0 :         basegfx::B2DHomMatrix aNewTransform;
     530             : 
     531             :         // add size to new transform
     532           0 :         aNewTransform.scale(rInfo.maBulletSize.getWidth(), rInfo.maBulletSize.getHeight());
     533             : 
     534             :         // apply transformA
     535           0 :         aNewTransform *= maNewTransformA;
     536             : 
     537             :         // apply local offset
     538           0 :         aNewTransform.translate(rInfo.maBulletPosition.X(), rInfo.maBulletPosition.Y());
     539             : 
     540             :         // also apply embedding object's transform
     541           0 :         aNewTransform *= maNewTransformB;
     542             : 
     543             :         // prepare empty GraphicAttr
     544           0 :         const GraphicAttr aGraphicAttr;
     545             : 
     546             :         // create GraphicPrimitive2D
     547             :         const drawinglayer::primitive2d::Primitive2DReference aNewReference(new drawinglayer::primitive2d::GraphicPrimitive2D(
     548             :             aNewTransform,
     549             :             rInfo.maBulletGraphicObject,
     550           0 :             aGraphicAttr));
     551             : 
     552             :         // embed in TextHierarchyBulletPrimitive2D
     553           0 :         const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(&aNewReference, 1);
     554           0 :         drawinglayer::primitive2d::BasePrimitive2D* pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence);
     555             : 
     556             :         // add to output
     557           0 :         maTextPortionPrimitives.push_back(pNewPrimitive);
     558           0 :     }
     559             : 
     560           0 :     IMPL_LINK(impTextBreakupHandler, decomposeContourTextPrimitive, DrawPortionInfo*, pInfo)
     561             :     {
     562             :         // for contour text, ignore (clip away) all portions which are below
     563             :         // the visible area given by maScale
     564           0 :         if(pInfo && (double)pInfo->mrStartPos.Y() < maScale.getY())
     565             :         {
     566           0 :             impHandleDrawPortionInfo(*pInfo);
     567             :         }
     568             : 
     569           0 :         return 0;
     570             :     }
     571             : 
     572       47578 :     IMPL_LINK(impTextBreakupHandler, decomposeBlockTextPrimitive, DrawPortionInfo*, pInfo)
     573             :     {
     574       23789 :         if(pInfo)
     575             :         {
     576             :             // Is clipping wanted? This is text clipping; only accept a portion
     577             :             // if it's completely in the range
     578       23789 :             if(!maClipRange.isEmpty())
     579             :             {
     580             :                 // Test start position first; this allows to not get the text range at
     581             :                 // all if text is far outside
     582           0 :                 const basegfx::B2DPoint aStartPosition(pInfo->mrStartPos.X(), pInfo->mrStartPos.Y());
     583             : 
     584           0 :                 if(!maClipRange.isInside(aStartPosition))
     585             :                 {
     586           0 :                     return 0;
     587             :                 }
     588             : 
     589             :                 // Start position is inside. Get TextBoundRect and TopLeft next
     590           0 :                 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
     591           0 :                 aTextLayouterDevice.setFont(pInfo->mrFont);
     592             : 
     593             :                 const basegfx::B2DRange aTextBoundRect(
     594             :                     aTextLayouterDevice.getTextBoundRect(
     595           0 :                         pInfo->maText, pInfo->mnTextStart, pInfo->mnTextLen));
     596           0 :                 const basegfx::B2DPoint aTopLeft(aTextBoundRect.getMinimum() + aStartPosition);
     597             : 
     598           0 :                 if(!maClipRange.isInside(aTopLeft))
     599             :                 {
     600           0 :                     return 0;
     601             :                 }
     602             : 
     603             :                 // TopLeft is inside. Get BottomRight and check
     604           0 :                 const basegfx::B2DPoint aBottomRight(aTextBoundRect.getMaximum() + aStartPosition);
     605             : 
     606           0 :                 if(!maClipRange.isInside(aBottomRight))
     607             :                 {
     608           0 :                     return 0;
     609           0 :                 }
     610             : 
     611             :                 // all inside, clip was successful
     612             :             }
     613       23789 :             impHandleDrawPortionInfo(*pInfo);
     614             :         }
     615             : 
     616       23789 :         return 0;
     617             :     }
     618             : 
     619           0 :     IMPL_LINK(impTextBreakupHandler, decomposeStretchTextPrimitive, DrawPortionInfo*, pInfo)
     620             :     {
     621           0 :         if(pInfo)
     622             :         {
     623           0 :             impHandleDrawPortionInfo(*pInfo);
     624             :         }
     625             : 
     626           0 :         return 0;
     627             :     }
     628             : 
     629           0 :     IMPL_LINK(impTextBreakupHandler, decomposeContourBulletPrimitive, DrawBulletInfo*, pInfo)
     630             :     {
     631           0 :         if(pInfo)
     632             :         {
     633           0 :             impHandleDrawBulletInfo(*pInfo);
     634             :         }
     635             : 
     636           0 :         return 0;
     637             :     }
     638             : 
     639           0 :     IMPL_LINK(impTextBreakupHandler, decomposeBlockBulletPrimitive, DrawBulletInfo*, pInfo)
     640             :     {
     641           0 :         if(pInfo)
     642             :         {
     643           0 :             impHandleDrawBulletInfo(*pInfo);
     644             :         }
     645             : 
     646           0 :         return 0;
     647             :     }
     648             : 
     649           0 :     IMPL_LINK(impTextBreakupHandler, decomposeStretchBulletPrimitive, DrawBulletInfo*, pInfo)
     650             :     {
     651           0 :         if(pInfo)
     652             :         {
     653           0 :             impHandleDrawBulletInfo(*pInfo);
     654             :         }
     655             : 
     656           0 :         return 0;
     657             :     }
     658             : 
     659       17483 :     drawinglayer::primitive2d::Primitive2DSequence impTextBreakupHandler::getPrimitive2DSequence()
     660             :     {
     661       17483 :         if(!maTextPortionPrimitives.empty())
     662             :         {
     663             :             // collect non-closed lines
     664           0 :             impFlushTextPortionPrimitivesToLinePrimitives();
     665             :         }
     666             : 
     667       17483 :         if(!maLinePrimitives.empty())
     668             :         {
     669             :             // collect non-closed paragraphs
     670           0 :             impFlushLinePrimitivesToParagraphPrimitives();
     671             :         }
     672             : 
     673       17483 :         return impConvertVectorToPrimitive2DSequence(maParagraphPrimitives);
     674             :     }
     675             : } // end of anonymous namespace
     676             : 
     677             : 
     678             : // primitive decompositions
     679             : 
     680           0 : void SdrTextObj::impDecomposeContourTextPrimitive(
     681             :     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     682             :     const drawinglayer::primitive2d::SdrContourTextPrimitive2D& rSdrContourTextPrimitive,
     683             :     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
     684             : {
     685             :     // decompose matrix to have position and size of text
     686           0 :     basegfx::B2DVector aScale, aTranslate;
     687             :     double fRotate, fShearX;
     688           0 :     rSdrContourTextPrimitive.getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
     689             : 
     690             :     // prepare contour polygon, force to non-mirrored for laying out
     691           0 :     basegfx::B2DPolyPolygon aPolyPolygon(rSdrContourTextPrimitive.getUnitPolyPolygon());
     692           0 :     aPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(fabs(aScale.getX()), fabs(aScale.getY())));
     693             : 
     694             :     // prepare outliner
     695           0 :     SdrOutliner& rOutliner = ImpGetDrawOutliner();
     696           0 :     const Size aNullSize;
     697           0 :     rOutliner.SetPaperSize(aNullSize);
     698           0 :     rOutliner.SetPolygon(aPolyPolygon);
     699           0 :     rOutliner.SetUpdateMode(true);
     700           0 :     rOutliner.SetText(rSdrContourTextPrimitive.getOutlinerParaObject());
     701             : 
     702             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
     703           0 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
     704             : 
     705             :     // prepare matrices to apply to newly created primitives
     706           0 :     basegfx::B2DHomMatrix aNewTransformA;
     707             : 
     708             :     // mirroring. We are now in the polygon sizes. When mirroring in X and Y,
     709             :     // move the null point which was top left to bottom right.
     710           0 :     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
     711           0 :     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
     712             : 
     713             :     // in-between the translations of the single primitives will take place. Afterwards,
     714             :     // the object's transformations need to be applied
     715             :     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
     716             :         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
     717           0 :         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
     718             : 
     719             :     // now break up text primitives.
     720           0 :     impTextBreakupHandler aConverter(rOutliner);
     721           0 :     aConverter.decomposeContourTextPrimitive(aNewTransformA, aNewTransformB, aScale);
     722             : 
     723             :     // cleanup outliner
     724           0 :     rOutliner.Clear();
     725           0 :     rOutliner.setVisualizedPage(0);
     726             : 
     727           0 :     rTarget = aConverter.getPrimitive2DSequence();
     728           0 : }
     729             : 
     730          71 : void SdrTextObj::impDecomposeAutoFitTextPrimitive(
     731             :     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     732             :     const drawinglayer::primitive2d::SdrAutoFitTextPrimitive2D& rSdrAutofitTextPrimitive,
     733             :     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
     734             : {
     735             :     // decompose matrix to have position and size of text
     736         142 :     basegfx::B2DVector aScale, aTranslate;
     737             :     double fRotate, fShearX;
     738          71 :     rSdrAutofitTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
     739             : 
     740             :     // use B2DRange aAnchorTextRange for calculations
     741          71 :     basegfx::B2DRange aAnchorTextRange(aTranslate);
     742          71 :     aAnchorTextRange.expand(aTranslate + aScale);
     743             : 
     744             :     // prepare outliner
     745          71 :     const SfxItemSet& rTextItemSet = rSdrAutofitTextPrimitive.getSdrText()->GetItemSet();
     746          71 :     SdrOutliner& rOutliner = ImpGetDrawOutliner();
     747          71 :     SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
     748          71 :     SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
     749          71 :     const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
     750          71 :     const Size aNullSize;
     751             : 
     752             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
     753          71 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
     754             : 
     755          71 :     rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
     756          71 :     rOutliner.SetMinAutoPaperSize(aNullSize);
     757          71 :     rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
     758             : 
     759             :     // add one to rage sizes to get back to the old Rectangle and outliner measurements
     760          71 :     const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1L));
     761          71 :     const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1L));
     762          71 :     const OutlinerParaObject* pOutlinerParaObject = rSdrAutofitTextPrimitive.getSdrText()->GetOutlinerParaObject();
     763             :     OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
     764          71 :     const bool bVerticalWritintg(pOutlinerParaObject->IsVertical());
     765          71 :     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
     766             : 
     767          71 :     if((rSdrAutofitTextPrimitive.getWordWrap() || IsTextFrame()))
     768             :     {
     769          71 :         rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
     770             :     }
     771             : 
     772          71 :     if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWritintg)
     773             :     {
     774          71 :         rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
     775             :     }
     776             : 
     777          71 :     if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWritintg)
     778             :     {
     779           0 :         rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
     780             :     }
     781             : 
     782          71 :     rOutliner.SetPaperSize(aNullSize);
     783          71 :     rOutliner.SetUpdateMode(true);
     784          71 :     rOutliner.SetText(*pOutlinerParaObject);
     785          71 :     ImpAutoFitText(rOutliner,aAnchorTextSize,bVerticalWritintg);
     786             : 
     787             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
     788          71 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
     789             : 
     790             :     // now get back the layouted text size from outliner
     791          71 :     const Size aOutlinerTextSize(rOutliner.GetPaperSize());
     792         142 :     const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
     793         142 :     basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
     794             : 
     795             :     // correct horizontal translation using the now known text size
     796          71 :     if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
     797             :     {
     798           0 :         const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
     799             : 
     800           0 :         if(SDRTEXTHORZADJUST_CENTER == eHAdj)
     801             :         {
     802           0 :             aAdjustTranslate.setX(fFree / 2.0);
     803             :         }
     804             : 
     805           0 :         if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
     806             :         {
     807           0 :             aAdjustTranslate.setX(fFree);
     808             :         }
     809             :     }
     810             : 
     811             :     // correct vertical translation using the now known text size
     812          71 :     if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
     813             :     {
     814           0 :         const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
     815             : 
     816           0 :         if(SDRTEXTVERTADJUST_CENTER == eVAdj)
     817             :         {
     818           0 :             aAdjustTranslate.setY(fFree / 2.0);
     819             :         }
     820             : 
     821           0 :         if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
     822             :         {
     823           0 :             aAdjustTranslate.setY(fFree);
     824             :         }
     825             :     }
     826             : 
     827             :     // prepare matrices to apply to newly created primitives. aNewTransformA
     828             :     // will get coordinates in aOutlinerScale size and positive in X, Y.
     829         142 :     basegfx::B2DHomMatrix aNewTransformA;
     830         142 :     basegfx::B2DHomMatrix aNewTransformB;
     831             : 
     832             :     // translate relative to given primitive to get same rotation and shear
     833             :     // as the master shape we are working on. For vertical, use the top-right
     834             :     // corner
     835          71 :     const double fStartInX(bVerticalWritintg ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
     836          71 :     aNewTransformA.translate(fStartInX, aAdjustTranslate.getY());
     837             : 
     838             :     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
     839             :     // move the null point which was top left to bottom right.
     840          71 :     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
     841          71 :     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
     842          71 :     aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
     843             : 
     844             :     // in-between the translations of the single primitives will take place. Afterwards,
     845             :     // the object's transformations need to be applied
     846          71 :     aNewTransformB.shearX(fShearX);
     847          71 :     aNewTransformB.rotate(fRotate);
     848          71 :     aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
     849             : 
     850          71 :     basegfx::B2DRange aClipRange;
     851             : 
     852             :     // now break up text primitives.
     853         142 :     impTextBreakupHandler aConverter(rOutliner);
     854          71 :     aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
     855             : 
     856             :     // cleanup outliner
     857          71 :     rOutliner.Clear();
     858          71 :     rOutliner.setVisualizedPage(0);
     859          71 :     rOutliner.SetControlWord(nOriginalControlWord);
     860             : 
     861         142 :     rTarget = aConverter.getPrimitive2DSequence();
     862          71 : }
     863             : 
     864       17412 : void SdrTextObj::impDecomposeBlockTextPrimitive(
     865             :     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     866             :     const drawinglayer::primitive2d::SdrBlockTextPrimitive2D& rSdrBlockTextPrimitive,
     867             :     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
     868             : {
     869             :     // decompose matrix to have position and size of text
     870       34824 :     basegfx::B2DVector aScale, aTranslate;
     871             :     double fRotate, fShearX;
     872       17412 :     rSdrBlockTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
     873             : 
     874             :     // use B2DRange aAnchorTextRange for calculations
     875       17412 :     basegfx::B2DRange aAnchorTextRange(aTranslate);
     876       17412 :     aAnchorTextRange.expand(aTranslate + aScale);
     877             : 
     878             :     // prepare outliner
     879       17412 :     const bool bIsCell(rSdrBlockTextPrimitive.getCellText());
     880       17412 :     SdrOutliner& rOutliner = ImpGetDrawOutliner();
     881       17412 :     SdrTextHorzAdjust eHAdj = rSdrBlockTextPrimitive.getSdrTextHorzAdjust();
     882       17412 :     SdrTextVertAdjust eVAdj = rSdrBlockTextPrimitive.getSdrTextVertAdjust();
     883       17412 :     const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
     884       17412 :     const Size aNullSize;
     885             : 
     886             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
     887       17412 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
     888       17412 :     rOutliner.SetFixedCellHeight(rSdrBlockTextPrimitive.isFixedCellHeight());
     889       17412 :     rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE);
     890       17412 :     rOutliner.SetMinAutoPaperSize(aNullSize);
     891       17412 :     rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
     892             : 
     893             :     // Resolves: fdo#35779 set background color of this shape as the editeng background if there
     894             :     // is one. Check the shape itself, then the host page, then that page's master page.
     895             :     // That color needs to be restored on leaving this method
     896       17412 :     Color aOriginalBackColor(rOutliner.GetBackgroundColor());
     897       17412 :     const SfxItemSet* pBackgroundFillSet = &GetObjectItemSet();
     898             : 
     899       17412 :     if (drawing::FillStyle_NONE == static_cast<const XFillStyleItem&>(pBackgroundFillSet->Get(XATTR_FILLSTYLE)).GetValue())
     900             :     {
     901       16207 :         SdrPage *pOwnerPage = GetPage();
     902       16207 :         if (pOwnerPage)
     903             :         {
     904       15861 :             pBackgroundFillSet = &pOwnerPage->getSdrPageProperties().GetItemSet();
     905             : 
     906       15861 :             if (drawing::FillStyle_NONE == static_cast<const XFillStyleItem&>(pBackgroundFillSet->Get(XATTR_FILLSTYLE)).GetValue())
     907             :             {
     908       14609 :                 if (!pOwnerPage->IsMasterPage() && pOwnerPage->TRG_HasMasterPage())
     909             :                 {
     910        1067 :                     pBackgroundFillSet = &pOwnerPage->TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
     911             :                 }
     912             :             }
     913             :         }
     914             :     }
     915             : 
     916       17412 :     if (drawing::FillStyle_NONE != static_cast<const XFillStyleItem&>(pBackgroundFillSet->Get(XATTR_FILLSTYLE)).GetValue())
     917             :     {
     918        2813 :         Color aColor(rOutliner.GetBackgroundColor());
     919        2813 :         GetDraftFillColor(*pBackgroundFillSet, aColor);
     920        2813 :         rOutliner.SetBackgroundColor(aColor);
     921             :     }
     922             : 
     923             :     // add one to rage sizes to get back to the old Rectangle and outliner measurements
     924       17412 :     const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1L));
     925       17412 :     const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1L));
     926       17412 :     const bool bVerticalWritintg(rSdrBlockTextPrimitive.getOutlinerParaObject().IsVertical());
     927       17412 :     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
     928             : 
     929       17412 :     if(bIsCell)
     930             :     {
     931             :         // cell text is formatted neither like a text object nor like a object
     932             :         // text, so use a special setup here
     933           0 :         rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
     934             : 
     935             :         // #i106214# To work with an unchangeable PaperSize (CellSize in
     936             :         // this case) Set(Min|Max)AutoPaperSize and SetPaperSize have to be used.
     937             :         // #i106214# This was not completely correct; to still measure the real
     938             :         // text height to allow vertical adjust (and vice versa for VerticalWritintg)
     939             :         // only one aspect has to be set, but the other one to zero
     940           0 :         if(bVerticalWritintg)
     941             :         {
     942             :             // measure the horizontal text size
     943           0 :             rOutliner.SetMinAutoPaperSize(Size(0, aAnchorTextSize.Height()));
     944             :         }
     945             :         else
     946             :         {
     947             :             // measure the vertical text size
     948           0 :             rOutliner.SetMinAutoPaperSize(Size(aAnchorTextSize.Width(), 0));
     949             :         }
     950             : 
     951           0 :         rOutliner.SetPaperSize(aAnchorTextSize);
     952           0 :         rOutliner.SetUpdateMode(true);
     953           0 :         rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
     954             :     }
     955             :     else
     956             :     {
     957             :         // check if block text is used (only one of them can be true)
     958       17412 :         const bool bHorizontalIsBlock(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWritintg);
     959       17412 :         const bool bVerticalIsBlock(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWritintg);
     960             : 
     961             :         // set minimal paper size horizontally/vertically if needed
     962       17412 :         if(bHorizontalIsBlock)
     963             :         {
     964        4399 :             rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
     965             :         }
     966       13013 :         else if(bVerticalIsBlock)
     967             :         {
     968           0 :             rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
     969             :         }
     970             : 
     971       17412 :         if((rSdrBlockTextPrimitive.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive.getUnlimitedPage())
     972             :         {
     973             :             // #i103454# maximal paper size hor/ver needs to be limited to text
     974             :             // frame size. If it's block text, still allow the 'other' direction
     975             :             // to grow to get a correct real text size when using GetPaperSize().
     976             :             // When just using aAnchorTextSize as maximum, GetPaperSize()
     977             :             // would just return aAnchorTextSize again: this means, the wanted
     978             :             // 'measurement' of the real size of block text would not work
     979       17311 :             Size aMaxAutoPaperSize(aAnchorTextSize);
     980             : 
     981       17311 :             if(bHorizontalIsBlock)
     982             :             {
     983             :                 // allow to grow vertical for horizontal blocks
     984        4339 :                 aMaxAutoPaperSize.setHeight(1000000);
     985             :             }
     986       12972 :             else if(bVerticalIsBlock)
     987             :             {
     988             :                 // allow to grow horizontal for vertical blocks
     989           0 :                 aMaxAutoPaperSize.setWidth(1000000);
     990             :             }
     991             : 
     992       17311 :             rOutliner.SetMaxAutoPaperSize(aMaxAutoPaperSize);
     993             :         }
     994             : 
     995       17412 :         rOutliner.SetPaperSize(aNullSize);
     996       17412 :         rOutliner.SetUpdateMode(true);
     997       17412 :         rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
     998             :     }
     999             : 
    1000       17412 :     rOutliner.SetControlWord(nOriginalControlWord);
    1001             : 
    1002             :     // now get back the layouted text size from outliner
    1003       17412 :     const Size aOutlinerTextSize(rOutliner.GetPaperSize());
    1004       34824 :     const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
    1005       34824 :     basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
    1006             : 
    1007             :     // For draw objects containing text correct hor/ver alignment if text is bigger
    1008             :     // than the object itself. Without that correction, the text would always be
    1009             :     // formatted to the left edge (or top edge when vertical) of the draw object.
    1010       17412 :     if(!IsTextFrame() && !bIsCell)
    1011             :     {
    1012         681 :         if(aAnchorTextRange.getWidth() < aOutlinerScale.getX() && !bVerticalWritintg)
    1013             :         {
    1014             :             // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
    1015             :             // else the alignment is wanted.
    1016         660 :             if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
    1017             :             {
    1018         634 :                 eHAdj = SDRTEXTHORZADJUST_CENTER;
    1019             :             }
    1020             :         }
    1021             : 
    1022         681 :         if(aAnchorTextRange.getHeight() < aOutlinerScale.getY() && bVerticalWritintg)
    1023             :         {
    1024             :             // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
    1025             :             // else the alignment is wanted.
    1026           0 :             if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
    1027             :             {
    1028           0 :                 eVAdj = SDRTEXTVERTADJUST_CENTER;
    1029             :             }
    1030             :         }
    1031             :     }
    1032             : 
    1033             :     // correct horizontal translation using the now known text size
    1034       17412 :     if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
    1035             :     {
    1036       10632 :         const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
    1037             : 
    1038       10632 :         if(SDRTEXTHORZADJUST_CENTER == eHAdj)
    1039             :         {
    1040        6033 :             aAdjustTranslate.setX(fFree / 2.0);
    1041             :         }
    1042             : 
    1043       10632 :         if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
    1044             :         {
    1045        4599 :             aAdjustTranslate.setX(fFree);
    1046             :         }
    1047             :     }
    1048             : 
    1049             :     // correct vertical translation using the now known text size
    1050       17412 :     if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
    1051             :     {
    1052        8052 :         const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
    1053             : 
    1054        8052 :         if(SDRTEXTVERTADJUST_CENTER == eVAdj)
    1055             :         {
    1056        6472 :             aAdjustTranslate.setY(fFree / 2.0);
    1057             :         }
    1058             : 
    1059        8052 :         if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
    1060             :         {
    1061        1580 :             aAdjustTranslate.setY(fFree);
    1062             :         }
    1063             :     }
    1064             : 
    1065             :     // prepare matrices to apply to newly created primitives. aNewTransformA
    1066             :     // will get coordinates in aOutlinerScale size and positive in X, Y.
    1067             :     // Translate relative to given primitive to get same rotation and shear
    1068             :     // as the master shape we are working on. For vertical, use the top-right
    1069             :     // corner
    1070       17412 :     const double fStartInX(bVerticalWritintg ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
    1071       34824 :     const basegfx::B2DTuple aAdjOffset(fStartInX, aAdjustTranslate.getY());
    1072       34824 :     basegfx::B2DHomMatrix aNewTransformA(basegfx::tools::createTranslateB2DHomMatrix(aAdjOffset.getX(), aAdjOffset.getY()));
    1073             : 
    1074             :     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
    1075             :     // move the null point which was top left to bottom right.
    1076       17412 :     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
    1077       17412 :     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
    1078             : 
    1079             :     // in-between the translations of the single primitives will take place. Afterwards,
    1080             :     // the object's transformations need to be applied
    1081             :     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
    1082             :         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
    1083       34824 :         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
    1084             : 
    1085             :     // create ClipRange (if needed)
    1086       17412 :     basegfx::B2DRange aClipRange;
    1087             : 
    1088       17412 :     if(rSdrBlockTextPrimitive.getClipOnBounds())
    1089             :     {
    1090           0 :         aClipRange.expand(-aAdjOffset);
    1091           0 :         aClipRange.expand(basegfx::B2DTuple(aAnchorTextSize.Width(), aAnchorTextSize.Height()) - aAdjOffset);
    1092             :     }
    1093             : 
    1094             :     // now break up text primitives.
    1095       34824 :     impTextBreakupHandler aConverter(rOutliner);
    1096       17412 :     aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
    1097             : 
    1098             :     // cleanup outliner
    1099       17412 :     rOutliner.SetBackgroundColor(aOriginalBackColor);
    1100       17412 :     rOutliner.Clear();
    1101       17412 :     rOutliner.setVisualizedPage(0);
    1102             : 
    1103       34824 :     rTarget = aConverter.getPrimitive2DSequence();
    1104       17412 : }
    1105             : 
    1106           0 : void SdrTextObj::impDecomposeStretchTextPrimitive(
    1107             :     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
    1108             :     const drawinglayer::primitive2d::SdrStretchTextPrimitive2D& rSdrStretchTextPrimitive,
    1109             :     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
    1110             : {
    1111             :     // decompose matrix to have position and size of text
    1112           0 :     basegfx::B2DVector aScale, aTranslate;
    1113             :     double fRotate, fShearX;
    1114           0 :     rSdrStretchTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
    1115             : 
    1116             :     // use non-mirrored B2DRange aAnchorTextRange for calculations
    1117           0 :     basegfx::B2DRange aAnchorTextRange(aTranslate);
    1118           0 :     aAnchorTextRange.expand(aTranslate + aScale);
    1119             : 
    1120             :     // prepare outliner
    1121           0 :     SdrOutliner& rOutliner = ImpGetDrawOutliner();
    1122           0 :     const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
    1123           0 :     const Size aNullSize;
    1124             : 
    1125           0 :     rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE);
    1126           0 :     rOutliner.SetFixedCellHeight(rSdrStretchTextPrimitive.isFixedCellHeight());
    1127           0 :     rOutliner.SetMinAutoPaperSize(aNullSize);
    1128           0 :     rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
    1129           0 :     rOutliner.SetPaperSize(aNullSize);
    1130           0 :     rOutliner.SetUpdateMode(true);
    1131           0 :     rOutliner.SetText(rSdrStretchTextPrimitive.getOutlinerParaObject());
    1132             : 
    1133             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
    1134           0 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
    1135             : 
    1136             :     // now get back the laid out text size from outliner
    1137           0 :     const Size aOutlinerTextSize(rOutliner.CalcTextSize());
    1138             :     const basegfx::B2DVector aOutlinerScale(
    1139           0 :         basegfx::fTools::equalZero(aOutlinerTextSize.Width()) ? 1.0 : aOutlinerTextSize.Width(),
    1140           0 :         basegfx::fTools::equalZero(aOutlinerTextSize.Height()) ? 1.0 : aOutlinerTextSize.Height());
    1141             : 
    1142             :     // prepare matrices to apply to newly created primitives
    1143           0 :     basegfx::B2DHomMatrix aNewTransformA;
    1144             : 
    1145             :     // #i101957# Check for vertical text. If used, aNewTransformA
    1146             :     // needs to translate the text initially around object width to orient
    1147             :     // it relative to the topper right instead of the topper left
    1148           0 :     const bool bVertical(rSdrStretchTextPrimitive.getOutlinerParaObject().IsVertical());
    1149             : 
    1150           0 :     if(bVertical)
    1151             :     {
    1152           0 :         aNewTransformA.translate(aScale.getX(), 0.0);
    1153             :     }
    1154             : 
    1155             :     // calculate global char stretching scale parameters. Use non-mirrored sizes
    1156             :     // to layout without mirroring
    1157           0 :     const double fScaleX(fabs(aScale.getX()) / aOutlinerScale.getX());
    1158           0 :     const double fScaleY(fabs(aScale.getY()) / aOutlinerScale.getY());
    1159           0 :     rOutliner.SetGlobalCharStretching((sal_Int16)FRound(fScaleX * 100.0), (sal_Int16)FRound(fScaleY * 100.0));
    1160             : 
    1161             :     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
    1162             :     // move the null point which was top left to bottom right.
    1163           0 :     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
    1164           0 :     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
    1165             : 
    1166             :     // in-between the translations of the single primitives will take place. Afterwards,
    1167             :     // the object's transformations need to be applied
    1168             :     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
    1169             :         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
    1170           0 :         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
    1171             : 
    1172             :     // now break up text primitives.
    1173           0 :     impTextBreakupHandler aConverter(rOutliner);
    1174           0 :     aConverter.decomposeStretchTextPrimitive(aNewTransformA, aNewTransformB);
    1175             : 
    1176             :     // cleanup outliner
    1177           0 :     rOutliner.SetControlWord(nOriginalControlWord);
    1178           0 :     rOutliner.Clear();
    1179           0 :     rOutliner.setVisualizedPage(0);
    1180             : 
    1181           0 :     rTarget = aConverter.getPrimitive2DSequence();
    1182           0 : }
    1183             : 
    1184             : 
    1185             : // timing generators
    1186             : #define ENDLESS_LOOP    (0xffffffff)
    1187             : #define ENDLESS_TIME    ((double)0xffffffff)
    1188             : #define PIXEL_DPI       (96.0)
    1189             : 
    1190           0 : void SdrTextObj::impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const
    1191             : {
    1192           0 :     if(SDRTEXTANI_BLINK == GetTextAniKind())
    1193             :     {
    1194             :         // get values
    1195           0 :         const SfxItemSet& rSet = GetObjectItemSet();
    1196           0 :         const sal_uInt32 nRepeat((sal_uInt32)static_cast<const SdrTextAniCountItem&>(rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
    1197           0 :         double fDelay((double)static_cast<const SdrTextAniDelayItem&>(rSet.Get(SDRATTR_TEXT_ANIDELAY)).GetValue());
    1198             : 
    1199           0 :         if(0.0 == fDelay)
    1200             :         {
    1201             :             // use default
    1202           0 :             fDelay = 250.0;
    1203             :         }
    1204             : 
    1205             :         // prepare loop and add
    1206           0 :         drawinglayer::animation::AnimationEntryLoop  aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
    1207           0 :         drawinglayer::animation::AnimationEntryFixed aStart(fDelay, 0.0);
    1208           0 :         aLoop.append(aStart);
    1209           0 :         drawinglayer::animation::AnimationEntryFixed aEnd(fDelay, 1.0);
    1210           0 :         aLoop.append(aEnd);
    1211           0 :         rAnimList.append(aLoop);
    1212             : 
    1213             :         // add stopped state if loop is not endless
    1214           0 :         if(0L != nRepeat)
    1215             :         {
    1216           0 :             bool bVisisbleWhenStopped(static_cast<const SdrTextAniStopInsideItem&>(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
    1217           0 :             drawinglayer::animation::AnimationEntryFixed aStop(ENDLESS_TIME, bVisisbleWhenStopped ? 0.0 : 1.0);
    1218           0 :             rAnimList.append(aStop);
    1219           0 :         }
    1220             :     }
    1221           0 : }
    1222             : 
    1223           0 : void impCreateScrollTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
    1224             : {
    1225           0 :     bool bVisisbleWhenStopped(static_cast<const SdrTextAniStopInsideItem&>(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
    1226           0 :     bool bVisisbleWhenStarted(static_cast<const SdrTextAniStartInsideItem&>(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE )).GetValue());
    1227           0 :     const sal_uInt32 nRepeat(static_cast<const SdrTextAniCountItem&>(rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
    1228             : 
    1229           0 :     if(bVisisbleWhenStarted)
    1230             :     {
    1231             :         // move from center to outside
    1232           0 :         drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
    1233           0 :         rAnimList.append(aInOut);
    1234             :     }
    1235             : 
    1236             :     // loop. In loop, move through
    1237           0 :     drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
    1238           0 :     drawinglayer::animation::AnimationEntryLinear aThrough(fTimeFullPath, fFrequency, bForward ? 0.0 : 1.0, bForward ? 1.0 : 0.0);
    1239           0 :     aLoop.append(aThrough);
    1240           0 :     rAnimList.append(aLoop);
    1241             : 
    1242           0 :     if(0L != nRepeat && bVisisbleWhenStopped)
    1243             :     {
    1244             :         // move from outside to center
    1245           0 :         drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
    1246           0 :         rAnimList.append(aOutIn);
    1247             : 
    1248             :         // add timing for staying at the end
    1249           0 :         drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
    1250           0 :         rAnimList.append(aEnd);
    1251           0 :     }
    1252           0 : }
    1253             : 
    1254           0 : void impCreateAlternateTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, double fRelativeTextLength, bool bForward, double fTimeFullPath, double fFrequency)
    1255             : {
    1256           0 :     if(basegfx::fTools::more(fRelativeTextLength, 0.5))
    1257             :     {
    1258             :         // this is the case when fTextLength > fFrameLength, text is bigger than animation frame.
    1259             :         // In that case, correct direction
    1260           0 :         bForward = !bForward;
    1261             :     }
    1262             : 
    1263           0 :     const double fStartPosition(bForward ? fRelativeTextLength : 1.0 - fRelativeTextLength);
    1264           0 :     const double fEndPosition(bForward ? 1.0 - fRelativeTextLength : fRelativeTextLength);
    1265           0 :     bool bVisisbleWhenStarted(static_cast<const SdrTextAniStartInsideItem&>(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE )).GetValue());
    1266           0 :     const sal_uInt32 nRepeat(static_cast<const SdrTextAniCountItem&>(rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
    1267             : 
    1268           0 :     if(!bVisisbleWhenStarted)
    1269             :     {
    1270             :         // move from outside to center
    1271           0 :         drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
    1272           0 :         rAnimList.append(aOutIn);
    1273             :     }
    1274             : 
    1275             :     // loop. In loop, move out and in again. fInnerMovePath may be negative when text is bigger then frame,
    1276             :     // so use absolute value
    1277           0 :     const double fInnerMovePath(fabs(1.0 - (fRelativeTextLength * 2.0)));
    1278           0 :     const double fTimeForInnerPath(fTimeFullPath * fInnerMovePath);
    1279           0 :     const double fHalfInnerPath(fTimeForInnerPath * 0.5);
    1280           0 :     const sal_uInt32 nDoubleRepeat(nRepeat / 2L);
    1281             : 
    1282           0 :     if(nDoubleRepeat || 0L == nRepeat)
    1283             :     {
    1284             :         // double forth and back loop
    1285           0 :         drawinglayer::animation::AnimationEntryLoop aLoop(nDoubleRepeat ? nDoubleRepeat : ENDLESS_LOOP);
    1286           0 :         drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
    1287           0 :         aLoop.append(aTime0);
    1288           0 :         drawinglayer::animation::AnimationEntryLinear aTime1(fTimeForInnerPath, fFrequency, fEndPosition, fStartPosition);
    1289           0 :         aLoop.append(aTime1);
    1290           0 :         drawinglayer::animation::AnimationEntryLinear aTime2(fHalfInnerPath, fFrequency, fStartPosition, 0.5);
    1291           0 :         aLoop.append(aTime2);
    1292           0 :         rAnimList.append(aLoop);
    1293             :     }
    1294             : 
    1295           0 :     if(nRepeat % 2L)
    1296             :     {
    1297             :         // repeat is uneven, so we need one more forth and back to center
    1298           0 :         drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
    1299           0 :         rAnimList.append(aTime0);
    1300           0 :         drawinglayer::animation::AnimationEntryLinear aTime1(fHalfInnerPath, fFrequency, fEndPosition, 0.5);
    1301           0 :         rAnimList.append(aTime1);
    1302             :     }
    1303             : 
    1304           0 :     if(0L != nRepeat)
    1305             :     {
    1306           0 :         bool bVisisbleWhenStopped(static_cast<const SdrTextAniStopInsideItem&>(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
    1307           0 :         if(bVisisbleWhenStopped)
    1308             :         {
    1309             :             // add timing for staying at the end
    1310           0 :             drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
    1311           0 :             rAnimList.append(aEnd);
    1312             :         }
    1313             :         else
    1314             :         {
    1315             :             // move from center to outside
    1316           0 :             drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
    1317           0 :             rAnimList.append(aInOut);
    1318             :         }
    1319             :     }
    1320           0 : }
    1321             : 
    1322           0 : void impCreateSlideTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
    1323             : {
    1324             :     // move in from outside, start outside
    1325           0 :     const double fStartPosition(bForward ? 0.0 : 1.0);
    1326           0 :     const sal_uInt32 nRepeat(static_cast<const SdrTextAniCountItem&>(rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
    1327             : 
    1328             :     // move from outside to center
    1329           0 :     drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
    1330           0 :     rAnimList.append(aOutIn);
    1331             : 
    1332             :     // loop. In loop, move out and in again
    1333           0 :     if(nRepeat > 1L || 0L == nRepeat)
    1334             :     {
    1335           0 :         drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat - 1L : ENDLESS_LOOP);
    1336           0 :         drawinglayer::animation::AnimationEntryLinear aTime0(fTimeFullPath * 0.5, fFrequency, 0.5, fStartPosition);
    1337           0 :         aLoop.append(aTime0);
    1338           0 :         drawinglayer::animation::AnimationEntryLinear aTime1(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
    1339           0 :         aLoop.append(aTime1);
    1340           0 :         rAnimList.append(aLoop);
    1341             :     }
    1342             : 
    1343             :     // always visible when stopped, so add timing for staying at the end when not endless
    1344           0 :     if(0L != nRepeat)
    1345             :     {
    1346           0 :         drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
    1347           0 :         rAnimList.append(aEnd);
    1348           0 :     }
    1349           0 : }
    1350             : 
    1351           0 : void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
    1352             : {
    1353           0 :     const SdrTextAniKind eAniKind(GetTextAniKind());
    1354             : 
    1355           0 :     if(SDRTEXTANI_SCROLL == eAniKind || SDRTEXTANI_ALTERNATE == eAniKind || SDRTEXTANI_SLIDE == eAniKind)
    1356             :     {
    1357             :         // get data. Goal is to calculate fTimeFullPath which is the time needed to
    1358             :         // move animation from (0.0) to (1.0) state
    1359           0 :         const SfxItemSet& rSet = GetObjectItemSet();
    1360           0 :         double fAnimationDelay((double)static_cast<const SdrTextAniDelayItem&>(rSet.Get(SDRATTR_TEXT_ANIDELAY)).GetValue());
    1361           0 :         double fSingleStepWidth((double)static_cast<const SdrTextAniAmountItem&>(rSet.Get(SDRATTR_TEXT_ANIAMOUNT)).GetValue());
    1362           0 :         const SdrTextAniDirection eDirection(GetTextAniDirection());
    1363           0 :         const bool bForward(SDRTEXTANI_RIGHT == eDirection || SDRTEXTANI_DOWN == eDirection);
    1364             : 
    1365           0 :         if(basegfx::fTools::equalZero(fAnimationDelay))
    1366             :         {
    1367             :             // default to 1/20 second
    1368           0 :             fAnimationDelay = 50.0;
    1369             :         }
    1370             : 
    1371           0 :         if(basegfx::fTools::less(fSingleStepWidth, 0.0))
    1372             :         {
    1373             :             // data is in pixels, convert to logic. Imply PIXEL_DPI dpi.
    1374             :             // It makes no sense to keep the view-transformation centered
    1375             :             // definitions, so get rid of them here.
    1376           0 :             fSingleStepWidth = (-fSingleStepWidth * (2540.0 / PIXEL_DPI));
    1377             :         }
    1378             : 
    1379           0 :         if(basegfx::fTools::equalZero(fSingleStepWidth))
    1380             :         {
    1381             :             // default to 1 millimeter
    1382           0 :             fSingleStepWidth = 100.0;
    1383             :         }
    1384             : 
    1385             :         // use the length of the full animation path and the number of steps
    1386             :         // to get the full path time
    1387           0 :         const double fFullPathLength(fFrameLength + fTextLength);
    1388           0 :         const double fNumberOfSteps(fFullPathLength / fSingleStepWidth);
    1389           0 :         double fTimeFullPath(fNumberOfSteps * fAnimationDelay);
    1390             : 
    1391           0 :         if(fTimeFullPath < fAnimationDelay)
    1392             :         {
    1393           0 :             fTimeFullPath = fAnimationDelay;
    1394             :         }
    1395             : 
    1396           0 :         switch(eAniKind)
    1397             :         {
    1398             :             case SDRTEXTANI_SCROLL :
    1399             :             {
    1400           0 :                 impCreateScrollTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
    1401           0 :                 break;
    1402             :             }
    1403             :             case SDRTEXTANI_ALTERNATE :
    1404             :             {
    1405           0 :                 double fRelativeTextLength(fTextLength / (fFrameLength + fTextLength));
    1406           0 :                 impCreateAlternateTiming(rSet, rAnimList, fRelativeTextLength, bForward, fTimeFullPath, fAnimationDelay);
    1407           0 :                 break;
    1408             :             }
    1409             :             case SDRTEXTANI_SLIDE :
    1410             :             {
    1411           0 :                 impCreateSlideTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
    1412           0 :                 break;
    1413             :             }
    1414           0 :             default : break; // SDRTEXTANI_NONE, SDRTEXTANI_BLINK
    1415             :         }
    1416             :     }
    1417         435 : }
    1418             : 
    1419             : 
    1420             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11