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

Generated by: LCOV version 1.10