LCOV - code coverage report
Current view: top level - libreoffice/svx/source/svdraw - svdotextpathdecomposition.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 286 0.0 %
Date: 2012-12-27 Functions: 0 28 0.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 <basegfx/range/b2drange.hxx>
      26             : #include <svl/itemset.hxx>
      27             : #include <basegfx/polygon/b2dpolygontools.hxx>
      28             : #include <basegfx/polygon/b2dpolygon.hxx>
      29             : #include <algorithm>
      30             : #include <svx/xtextit.hxx>
      31             : #include <svx/xftshtit.hxx>
      32             : #include <vcl/virdev.hxx>
      33             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      34             : #include <com/sun/star/i18n/ScriptType.hpp>
      35             : #include <com/sun/star/i18n/BreakIterator.hpp>
      36             : #include <comphelper/processfactory.hxx>
      37             : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
      38             : #include <editeng/unolingu.hxx>
      39             : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
      40             : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
      41             : #include <basegfx/color/bcolor.hxx>
      42             : 
      43             : //////////////////////////////////////////////////////////////////////////////
      44             : // primitive decomposition helpers
      45             : 
      46             : #include <basegfx/polygon/b2dlinegeometry.hxx>
      47             : #include <drawinglayer/attribute/strokeattribute.hxx>
      48             : #include <svx/xlnclit.hxx>
      49             : #include <svx/xlntrit.hxx>
      50             : #include <svx/xlnwtit.hxx>
      51             : #include <svx/xlinjoit.hxx>
      52             : #include <svx/xlndsit.hxx>
      53             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      54             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      55             : #include <editeng/editstat.hxx>
      56             : #include <svx/unoapi.hxx>
      57             : #include <drawinglayer/geometry/viewinformation2d.hxx>
      58             : #include <svx/sdr/attribute/sdrformtextoutlineattribute.hxx>
      59             : 
      60             : //////////////////////////////////////////////////////////////////////////////
      61             : 
      62             : using namespace ::com::sun::star::uno;
      63             : using namespace ::com::sun::star::lang;
      64             : using namespace ::com::sun::star::i18n;
      65             : 
      66             : //////////////////////////////////////////////////////////////////////////////
      67             : // PathTextPortion helper
      68             : 
      69             : namespace
      70             : {
      71           0 :     class impPathTextPortion
      72             :     {
      73             :         basegfx::B2DVector                          maOffset;
      74             :         String                                      maText;
      75             :         xub_StrLen                                  mnTextStart;
      76             :         xub_StrLen                                  mnTextLength;
      77             :         sal_uInt16                                  mnParagraph;
      78             :         xub_StrLen                                  mnIndex;
      79             :         SvxFont                                     maFont;
      80             :         ::std::vector< double >                     maDblDXArray;   // double DXArray, font size independent -> unit coordinate system
      81             :         ::com::sun::star::lang::Locale              maLocale;
      82             : 
      83             :         // bitfield
      84             :         unsigned                                    mbRTL : 1;
      85             : 
      86             :     public:
      87           0 :         impPathTextPortion(DrawPortionInfo& rInfo)
      88           0 :         :   maOffset(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y()),
      89             :             maText(rInfo.mrText),
      90             :             mnTextStart(rInfo.mnTextStart),
      91             :             mnTextLength(rInfo.mnTextLen),
      92             :             mnParagraph(rInfo.mnPara),
      93             :             mnIndex(rInfo.mnIndex),
      94             :             maFont(rInfo.mrFont),
      95             :             maDblDXArray(),
      96             :             maLocale(rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale()),
      97           0 :             mbRTL(rInfo.mrFont.IsVertical() ? false : rInfo.IsRTL())
      98             :         {
      99           0 :             if(mnTextLength && rInfo.mpDXArray)
     100             :             {
     101           0 :                 maDblDXArray.reserve(mnTextLength);
     102             : 
     103           0 :                 for(xub_StrLen a(0); a < mnTextLength; a++)
     104             :                 {
     105           0 :                     maDblDXArray.push_back((double)rInfo.mpDXArray[a]);
     106             :                 }
     107             :             }
     108           0 :         }
     109             : 
     110             :         // for ::std::sort
     111           0 :         bool operator<(const impPathTextPortion& rComp) const
     112             :         {
     113           0 :             if(mnParagraph < rComp.mnParagraph)
     114             :             {
     115           0 :                 return true;
     116             :             }
     117             : 
     118           0 :             if(maOffset.getX() < rComp.maOffset.getX())
     119             :             {
     120           0 :                 return true;
     121             :             }
     122             : 
     123           0 :             return (maOffset.getY() < rComp.maOffset.getY());
     124             :         }
     125             : 
     126             :         const basegfx::B2DVector& getOffset() const { return maOffset; }
     127           0 :         const String& getText() const { return maText; }
     128           0 :         xub_StrLen getTextStart() const { return mnTextStart; }
     129           0 :         xub_StrLen getTextLength() const { return mnTextLength; }
     130           0 :         sal_uInt16 getParagraph() const { return mnParagraph; }
     131             :         xub_StrLen getIndex() const { return mnIndex; }
     132           0 :         const SvxFont& getFont() const { return maFont; }
     133           0 :         bool isRTL() const { return mbRTL; }
     134           0 :         const ::std::vector< double >& getDoubleDXArray() const { return maDblDXArray; }
     135           0 :         const ::com::sun::star::lang::Locale& getLocale() const { return maLocale; }
     136             : 
     137           0 :         xub_StrLen getPortionIndex(xub_StrLen nIndex, xub_StrLen nLength) const
     138             :         {
     139           0 :             if(mbRTL)
     140             :             {
     141           0 :                 return (mnTextStart + (mnTextLength - (nIndex + nLength)));
     142             :             }
     143             :             else
     144             :             {
     145           0 :                 return (mnTextStart + nIndex);
     146             :             }
     147             :         }
     148             : 
     149           0 :         double getDisplayLength(xub_StrLen nIndex, xub_StrLen nLength) const
     150             :         {
     151           0 :             drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
     152           0 :             double fRetval(0.0);
     153             : 
     154           0 :             if(maFont.IsVertical())
     155             :             {
     156           0 :                 fRetval = aTextLayouter.getTextHeight() * (double)nLength;
     157             :             }
     158             :             else
     159             :             {
     160           0 :                 fRetval = aTextLayouter.getTextWidth(maText, getPortionIndex(nIndex, nLength), nLength);
     161             :             }
     162             : 
     163           0 :             return fRetval;
     164             :         }
     165             :     };
     166             : } // end of anonymous namespace
     167             : 
     168             : //////////////////////////////////////////////////////////////////////////////
     169             : // TextBreakup helper
     170             : 
     171             : namespace
     172             : {
     173           0 :     class impTextBreakupHandler
     174             :     {
     175             :         SdrOutliner&                                mrOutliner;
     176             :         ::std::vector< impPathTextPortion >         maPathTextPortions;
     177             : 
     178             :         DECL_LINK(decompositionPathTextPrimitive, DrawPortionInfo* );
     179             : 
     180             :     public:
     181           0 :         impTextBreakupHandler(SdrOutliner& rOutliner)
     182           0 :         :   mrOutliner(rOutliner)
     183             :         {
     184           0 :         }
     185             : 
     186           0 :         const ::std::vector< impPathTextPortion >& decompositionPathTextPrimitive()
     187             :         {
     188             :             // strip portions to maPathTextPortions
     189           0 :             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decompositionPathTextPrimitive));
     190           0 :             mrOutliner.StripPortions();
     191             : 
     192           0 :             if(!maPathTextPortions.empty())
     193             :             {
     194             :                 // sort portions by paragraph, x and y
     195           0 :                 ::std::sort(maPathTextPortions.begin(), maPathTextPortions.end());
     196             :             }
     197             : 
     198           0 :             return maPathTextPortions;
     199             :         }
     200             :     };
     201             : 
     202           0 :     IMPL_LINK(impTextBreakupHandler, decompositionPathTextPrimitive, DrawPortionInfo*, pInfo)
     203             :     {
     204           0 :         maPathTextPortions.push_back(impPathTextPortion(*pInfo));
     205           0 :         return 0;
     206             :     }
     207             : } // end of anonymous namespace
     208             : 
     209             : //////////////////////////////////////////////////////////////////////////////
     210             : // TextBreakup one poly and one paragraph helper
     211             : 
     212             : namespace
     213             : {
     214           0 :     class impPolygonParagraphHandler
     215             :     {
     216             :         const drawinglayer::attribute::SdrFormTextAttribute         maSdrFormTextAttribute; // FormText parameters
     217             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& mrDecomposition;        // destination primitive list
     218             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& mrShadowDecomposition;  // destination primitive list for shadow
     219             :         Reference < com::sun::star::i18n::XBreakIterator >          mxBreak;                // break iterator
     220             : 
     221           0 :         double getParagraphTextLength(const ::std::vector< const impPathTextPortion* >& rTextPortions)
     222             :         {
     223           0 :             drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
     224           0 :             double fRetval(0.0);
     225             : 
     226           0 :             for(sal_uInt32 a(0L); a < rTextPortions.size(); a++)
     227             :             {
     228           0 :                 const impPathTextPortion* pCandidate = rTextPortions[a];
     229             : 
     230           0 :                 if(pCandidate && pCandidate->getTextLength())
     231             :                 {
     232           0 :                     aTextLayouter.setFont(pCandidate->getFont());
     233           0 :                     fRetval += pCandidate->getDisplayLength(0L, pCandidate->getTextLength());
     234             :                 }
     235             :             }
     236             : 
     237           0 :             return fRetval;
     238             :         }
     239             : 
     240           0 :         xub_StrLen getNextGlyphLen(const impPathTextPortion* pCandidate, xub_StrLen nPosition, const ::com::sun::star::lang::Locale& rFontLocale)
     241             :         {
     242           0 :             xub_StrLen nNextGlyphLen(1);
     243             : 
     244           0 :             if(mxBreak.is())
     245             :             {
     246           0 :                 sal_Int32 nDone(0L);
     247           0 :                 nNextGlyphLen = (xub_StrLen)mxBreak->nextCharacters(pCandidate->getText(), nPosition,
     248           0 :                     rFontLocale, CharacterIteratorMode::SKIPCELL, 1, nDone) - nPosition;
     249             :             }
     250             : 
     251           0 :             return nNextGlyphLen;
     252             :         }
     253             : 
     254             :     public:
     255           0 :         impPolygonParagraphHandler(
     256             :             const drawinglayer::attribute::SdrFormTextAttribute& rSdrFormTextAttribute,
     257             :             std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rDecomposition,
     258             :             std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rShadowDecomposition)
     259             :         :   maSdrFormTextAttribute(rSdrFormTextAttribute),
     260             :             mrDecomposition(rDecomposition),
     261           0 :             mrShadowDecomposition(rShadowDecomposition)
     262             :         {
     263             :             // prepare BreakIterator
     264           0 :             Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
     265           0 :             mxBreak = com::sun::star::i18n::BreakIterator::create(xContext);
     266           0 :         }
     267             : 
     268           0 :         void HandlePair(const basegfx::B2DPolygon rPolygonCandidate, const ::std::vector< const impPathTextPortion* >& rTextPortions)
     269             :         {
     270             :             // prepare polygon geometry, take into account as many parameters as possible
     271           0 :             basegfx::B2DPolygon aPolygonCandidate(rPolygonCandidate);
     272           0 :             const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate));
     273           0 :             double fPolyEnd(fPolyLength);
     274           0 :             double fPolyStart(0.0);
     275           0 :             double fAutosizeScaleFactor(1.0);
     276           0 :             bool bAutosizeScale(false);
     277             : 
     278           0 :             if(maSdrFormTextAttribute.getFormTextMirror())
     279             :             {
     280           0 :                 aPolygonCandidate.flip();
     281             :             }
     282             : 
     283           0 :             if(maSdrFormTextAttribute.getFormTextStart()
     284           0 :                 && (XFT_LEFT == maSdrFormTextAttribute.getFormTextAdjust()
     285           0 :                     || XFT_RIGHT == maSdrFormTextAttribute.getFormTextAdjust()))
     286             :             {
     287           0 :                 if(XFT_LEFT == maSdrFormTextAttribute.getFormTextAdjust())
     288             :                 {
     289           0 :                     fPolyStart += maSdrFormTextAttribute.getFormTextStart();
     290             : 
     291           0 :                     if(fPolyStart > fPolyEnd)
     292             :                     {
     293           0 :                         fPolyStart = fPolyEnd;
     294             :                     }
     295             :                 }
     296             :                 else
     297             :                 {
     298           0 :                     fPolyEnd -= maSdrFormTextAttribute.getFormTextStart();
     299             : 
     300           0 :                     if(fPolyEnd < fPolyStart)
     301             :                     {
     302           0 :                         fPolyEnd = fPolyStart;
     303             :                     }
     304             :                 }
     305             :             }
     306             : 
     307           0 :             if(XFT_LEFT != maSdrFormTextAttribute.getFormTextAdjust())
     308             :             {
     309             :                 // calculate total text length of this paragraph, some layout needs to be done
     310           0 :                 const double fParagraphTextLength(getParagraphTextLength(rTextPortions));
     311             : 
     312             :                 // check if text is too long for paragraph. If yes, handle as if left aligned (default),
     313             :                 // but still take care of XFT_AUTOSIZE in that case
     314           0 :                 const bool bTextTooLong(fParagraphTextLength > (fPolyEnd - fPolyStart));
     315             : 
     316           0 :                 if(XFT_RIGHT == maSdrFormTextAttribute.getFormTextAdjust())
     317             :                 {
     318           0 :                     if(!bTextTooLong)
     319             :                     {
     320             :                         // if right aligned, add difference to polygon start
     321           0 :                         fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength);
     322             :                     }
     323             :                 }
     324           0 :                 else if(XFT_CENTER == maSdrFormTextAttribute.getFormTextAdjust())
     325             :                 {
     326           0 :                     if(!bTextTooLong)
     327             :                     {
     328             :                         // if centered, add half of difference to polygon start
     329           0 :                         fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength) / 2.0;
     330             :                     }
     331             :                 }
     332           0 :                 else if(XFT_AUTOSIZE == maSdrFormTextAttribute.getFormTextAdjust())
     333             :                 {
     334             :                     // if scale, prepare scale factor between curve length and text length
     335           0 :                     if(0.0 != fParagraphTextLength)
     336             :                     {
     337           0 :                         fAutosizeScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength;
     338           0 :                         bAutosizeScale = true;
     339             :                     }
     340             :                 }
     341             :             }
     342             : 
     343             :             // handle text portions for this paragraph
     344           0 :             for(sal_uInt32 a(0L); a < rTextPortions.size() && fPolyStart < fPolyEnd; a++)
     345             :             {
     346           0 :                 const impPathTextPortion* pCandidate = rTextPortions[a];
     347           0 :                 basegfx::B2DVector aFontScaling;
     348             : 
     349           0 :                 if(pCandidate && pCandidate->getTextLength())
     350             :                 {
     351             :                     const drawinglayer::attribute::FontAttribute aCandidateFontAttribute(
     352             :                         drawinglayer::primitive2d::getFontAttributeFromVclFont(
     353             :                             aFontScaling,
     354           0 :                             pCandidate->getFont(),
     355           0 :                             pCandidate->isRTL(),
     356           0 :                             false));
     357             : 
     358           0 :                     drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
     359           0 :                     aTextLayouter.setFont(pCandidate->getFont());
     360           0 :                     xub_StrLen nUsedTextLength(0);
     361             : 
     362           0 :                     while(nUsedTextLength < pCandidate->getTextLength() && fPolyStart < fPolyEnd)
     363             :                     {
     364           0 :                         xub_StrLen nNextGlyphLen(getNextGlyphLen(pCandidate, pCandidate->getTextStart() + nUsedTextLength, pCandidate->getLocale()));
     365             : 
     366             :                         // prepare portion length. Takes RTL sections into account.
     367           0 :                         double fPortionLength(pCandidate->getDisplayLength(nUsedTextLength, nNextGlyphLen));
     368             : 
     369           0 :                         if(bAutosizeScale)
     370             :                         {
     371             :                             // when autosize scaling, expand portion length
     372           0 :                             fPortionLength *= fAutosizeScaleFactor;
     373             :                         }
     374             : 
     375             :                         // create transformation
     376           0 :                         basegfx::B2DHomMatrix aNewTransformA, aNewTransformB, aNewShadowTransform;
     377           0 :                         basegfx::B2DPoint aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart, fPolyLength));
     378           0 :                         basegfx::B2DPoint aEndPos(aStartPos);
     379             : 
     380             :                         // add font scaling
     381           0 :                         aNewTransformA.scale(aFontScaling.getX(), aFontScaling.getY());
     382             : 
     383             :                         // prepare scaling of text primitive
     384           0 :                         if(bAutosizeScale)
     385             :                         {
     386             :                             // when autosize scaling, expand text primitive scaling to it
     387           0 :                             aNewTransformA.scale(fAutosizeScaleFactor, fAutosizeScaleFactor);
     388             :                         }
     389             : 
     390             :                         // eventually create shadow primitives from aDecomposition and add to rDecomposition
     391           0 :                         const bool bShadow(XFTSHADOW_NONE != maSdrFormTextAttribute.getFormTextShadow());
     392             : 
     393           0 :                         if(bShadow)
     394             :                         {
     395           0 :                             if(XFTSHADOW_NORMAL == maSdrFormTextAttribute.getFormTextShadow())
     396             :                             {
     397             :                                 aNewShadowTransform.translate(
     398           0 :                                     maSdrFormTextAttribute.getFormTextShdwXVal(),
     399           0 :                                     -maSdrFormTextAttribute.getFormTextShdwYVal());
     400             :                             }
     401             :                             else // XFTSHADOW_SLANT
     402             :                             {
     403           0 :                                 double fScaleValue(maSdrFormTextAttribute.getFormTextShdwYVal() / 100.0);
     404           0 :                                 double fShearValue(-maSdrFormTextAttribute.getFormTextShdwXVal() * F_PI1800);
     405             : 
     406           0 :                                 aNewShadowTransform.scale(1.0, fScaleValue);
     407           0 :                                 aNewShadowTransform.shearX(sin(fShearValue));
     408           0 :                                 aNewShadowTransform.scale(1.0, cos(fShearValue));
     409             :                             }
     410             :                         }
     411             : 
     412           0 :                         switch(maSdrFormTextAttribute.getFormTextStyle())
     413             :                         {
     414             :                             case XFT_ROTATE :
     415             :                             {
     416           0 :                                 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
     417           0 :                                 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
     418           0 :                                 aNewTransformB.rotate(atan2(aDirection.getY(), aDirection.getX()));
     419           0 :                                 aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
     420             : 
     421           0 :                                 break;
     422             :                             }
     423             :                             case XFT_UPRIGHT :
     424             :                             {
     425           0 :                                 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
     426             : 
     427           0 :                                 break;
     428             :                             }
     429             :                             case XFT_SLANTX :
     430             :                             {
     431           0 :                                 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
     432           0 :                                 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
     433           0 :                                 const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
     434           0 :                                 const double fSin(sin(fShearValue));
     435           0 :                                 const double fCos(cos(fShearValue));
     436             : 
     437           0 :                                    aNewTransformB.shearX(-fSin);
     438             : 
     439             :                                 // Scale may lead to objects without height since fCos == 0.0 is possible.
     440             :                                 // Renderers need to handle that, it's not a forbidden value and does not
     441             :                                 // need to be avoided
     442           0 :                                 aNewTransformB.scale(1.0, fCos);
     443           0 :                                 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
     444             : 
     445           0 :                                 break;
     446             :                             }
     447             :                             case XFT_SLANTY :
     448             :                             {
     449           0 :                                 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
     450           0 :                                 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
     451           0 :                                 const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
     452           0 :                                 const double fCos(cos(fShearValue));
     453           0 :                                 const double fTan(tan(fShearValue));
     454             : 
     455             :                                 // shear to 'stand' on the curve
     456           0 :                                 aNewTransformB.shearY(fTan);
     457             : 
     458             :                                 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
     459             :                                 // lead to primitives without width which the renderers will handle
     460           0 :                                    aNewTransformA.scale(fCos, 1.0);
     461             : 
     462           0 :                                 aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
     463             : 
     464           0 :                                 break;
     465             :                             }
     466           0 :                             default : break; // XFT_NONE
     467             :                         }
     468             : 
     469             :                         // distance from path?
     470           0 :                         if(maSdrFormTextAttribute.getFormTextDistance())
     471             :                         {
     472           0 :                             if(aEndPos.equal(aStartPos))
     473             :                             {
     474           0 :                                 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
     475             :                             }
     476             : 
     477             :                             // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
     478             :                             const basegfx::B2DVector aPerpendicular(
     479             :                                 basegfx::getNormalizedPerpendicular(aStartPos - aEndPos) *
     480           0 :                                 maSdrFormTextAttribute.getFormTextDistance());
     481           0 :                             aNewTransformB.translate(aPerpendicular.getX(), aPerpendicular.getY());
     482             :                         }
     483             : 
     484           0 :                         if(pCandidate->getText().Len() && nNextGlyphLen)
     485             :                         {
     486           0 :                             const xub_StrLen nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen));
     487           0 :                             ::std::vector< double > aNewDXArray;
     488             : 
     489           0 :                             if(nNextGlyphLen > 1 && pCandidate->getDoubleDXArray().size())
     490             :                             {
     491             :                                 // copy DXArray for portion
     492             :                                 aNewDXArray.insert(
     493             :                                     aNewDXArray.begin(),
     494           0 :                                     pCandidate->getDoubleDXArray().begin() + nPortionIndex,
     495           0 :                                     pCandidate->getDoubleDXArray().begin() + (nPortionIndex + nNextGlyphLen));
     496             : 
     497           0 :                                 if(nPortionIndex > 0)
     498             :                                 {
     499             :                                     // adapt to portion start
     500           0 :                                     double fDXOffset= *(pCandidate->getDoubleDXArray().begin() + (nPortionIndex - 1));
     501             :                                     ::std::transform(
     502             :                                         aNewDXArray.begin(), aNewDXArray.end(),
     503           0 :                                         aNewDXArray.begin(), ::std::bind2nd(::std::minus<double>(), fDXOffset));
     504             :                                 }
     505             : 
     506           0 :                                 if(bAutosizeScale)
     507             :                                 {
     508             :                                     // when autosize scaling, adapt to DXArray, too
     509             :                                     ::std::transform(
     510             :                                         aNewDXArray.begin(), aNewDXArray.end(),
     511           0 :                                         aNewDXArray.begin(), ::std::bind2nd(::std::multiplies<double>(), fAutosizeScaleFactor));
     512             :                                 }
     513             :                             }
     514             : 
     515           0 :                             if(bShadow)
     516             :                             {
     517             :                                 // shadow primitive creation
     518           0 :                                 const Color aShadowColor(maSdrFormTextAttribute.getFormTextShdwColor());
     519           0 :                                 const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());
     520             : 
     521             :                                 drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew =
     522             :                                     new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
     523             :                                         aNewTransformB * aNewShadowTransform * aNewTransformA,
     524             :                                         pCandidate->getText(),
     525             :                                         nPortionIndex,
     526             :                                         nNextGlyphLen,
     527             :                                         aNewDXArray,
     528             :                                         aCandidateFontAttribute,
     529             :                                         pCandidate->getLocale(),
     530           0 :                                         aRGBShadowColor);
     531             : 
     532           0 :                                 mrShadowDecomposition.push_back(pNew);
     533             :                             }
     534             : 
     535             :                             {
     536             :                                 // primitive creation
     537           0 :                                 const Color aColor(pCandidate->getFont().GetColor());
     538           0 :                                 const basegfx::BColor aRGBColor(aColor.getBColor());
     539             : 
     540             :                                 drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew =
     541             :                                     new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
     542             :                                         aNewTransformB * aNewTransformA,
     543             :                                         pCandidate->getText(),
     544             :                                         nPortionIndex,
     545             :                                         nNextGlyphLen,
     546             :                                         aNewDXArray,
     547             :                                         aCandidateFontAttribute,
     548             :                                         pCandidate->getLocale(),
     549           0 :                                         aRGBColor);
     550             : 
     551           0 :                                 mrDecomposition.push_back(pNew);
     552           0 :                             }
     553             :                         }
     554             : 
     555             :                         // consume from portion // no += here, xub_StrLen is sal_uInt16 and the compiler will generate a warning here
     556           0 :                         nUsedTextLength = nUsedTextLength + nNextGlyphLen;
     557             : 
     558             :                         // consume from polygon
     559           0 :                         fPolyStart += fPortionLength;
     560           0 :                     }
     561             :                 }
     562           0 :             }
     563           0 :         }
     564             :     };
     565             : } // end of anonymous namespace
     566             : 
     567             : //////////////////////////////////////////////////////////////////////////////
     568             : // primitive decomposition helpers
     569             : 
     570             : namespace
     571             : {
     572           0 :     void impAddPolygonStrokePrimitives(
     573             :         const basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
     574             :         const basegfx::B2DHomMatrix& rTransform,
     575             :         const drawinglayer::attribute::LineAttribute& rLineAttribute,
     576             :         const drawinglayer::attribute::StrokeAttribute& rStrokeAttribute,
     577             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rTarget)
     578             :     {
     579           0 :         for(basegfx::B2DPolyPolygonVector::const_iterator aPolygon(rB2DPolyPolyVector.begin()); aPolygon != rB2DPolyPolyVector.end(); ++aPolygon)
     580             :         {
     581             :             // prepare PolyPolygons
     582           0 :             basegfx::B2DPolyPolygon aB2DPolyPolygon = *aPolygon;
     583           0 :             aB2DPolyPolygon.transform(rTransform);
     584             : 
     585           0 :             for(sal_uInt32 a(0L); a < aB2DPolyPolygon.count(); a++)
     586             :             {
     587             :                 // create one primitive per polygon
     588             :                 drawinglayer::primitive2d::PolygonStrokePrimitive2D* pNew =
     589             :                     new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
     590           0 :                         aB2DPolyPolygon.getB2DPolygon(a), rLineAttribute, rStrokeAttribute);
     591           0 :                 rTarget.push_back(pNew);
     592             :             }
     593           0 :         }
     594           0 :     }
     595             : 
     596           0 :     drawinglayer::primitive2d::Primitive2DSequence impAddPathTextOutlines(
     597             :         const std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rSource,
     598             :         const drawinglayer::attribute::SdrFormTextOutlineAttribute& rOutlineAttribute)
     599             :     {
     600           0 :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aNewPrimitives;
     601             : 
     602           0 :         for(sal_uInt32 a(0L); a < rSource.size(); a++)
     603             :         {
     604           0 :             const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pTextCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(rSource[a]);
     605             : 
     606           0 :             if(pTextCandidate)
     607             :             {
     608           0 :                 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
     609           0 :                 basegfx::B2DHomMatrix aPolygonTransform;
     610             : 
     611             :                 // get text outlines and their object transformation
     612           0 :                 pTextCandidate->getTextOutlinesAndTransformation(aB2DPolyPolyVector, aPolygonTransform);
     613             : 
     614           0 :                 if(!aB2DPolyPolyVector.empty())
     615             :                 {
     616             :                     // create stroke primitives
     617           0 :                     std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aStrokePrimitives;
     618             :                     impAddPolygonStrokePrimitives(
     619             :                         aB2DPolyPolyVector,
     620             :                         aPolygonTransform,
     621           0 :                         rOutlineAttribute.getLineAttribute(),
     622           0 :                         rOutlineAttribute.getStrokeAttribute(),
     623           0 :                         aStrokePrimitives);
     624           0 :                     const sal_uInt32 nStrokeCount(aStrokePrimitives.size());
     625             : 
     626           0 :                     if(nStrokeCount)
     627             :                     {
     628           0 :                         if(rOutlineAttribute.getTransparence())
     629             :                         {
     630             :                             // create UnifiedTransparencePrimitive2D
     631           0 :                             drawinglayer::primitive2d::Primitive2DSequence aStrokePrimitiveSequence(nStrokeCount);
     632             : 
     633           0 :                             for(sal_uInt32 b(0L); b < nStrokeCount; b++)
     634             :                             {
     635           0 :                                 aStrokePrimitiveSequence[b] = drawinglayer::primitive2d::Primitive2DReference(aStrokePrimitives[b]);
     636             :                             }
     637             : 
     638             :                             drawinglayer::primitive2d::UnifiedTransparencePrimitive2D* pNew2 =
     639             :                                 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
     640             :                                     aStrokePrimitiveSequence,
     641           0 :                                     (double)rOutlineAttribute.getTransparence() / 100.0);
     642           0 :                             aNewPrimitives.push_back(pNew2);
     643             :                         }
     644             :                         else
     645             :                         {
     646             :                             // add polygons to rDecomposition as polygonStrokePrimitives
     647           0 :                             aNewPrimitives.insert(aNewPrimitives.end(), aStrokePrimitives.begin(), aStrokePrimitives.end());
     648             :                         }
     649           0 :                     }
     650           0 :                 }
     651             :             }
     652             :         }
     653             : 
     654           0 :         const sal_uInt32 nNewCount(aNewPrimitives.size());
     655             : 
     656           0 :         if(nNewCount)
     657             :         {
     658           0 :             drawinglayer::primitive2d::Primitive2DSequence aRetval(nNewCount);
     659             : 
     660           0 :             for(sal_uInt32 a(0L); a < nNewCount; a++)
     661             :             {
     662           0 :                 aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives[a]);
     663             :             }
     664             : 
     665           0 :             return aRetval;
     666             :         }
     667             :         else
     668             :         {
     669           0 :             return drawinglayer::primitive2d::Primitive2DSequence();
     670           0 :         }
     671             :     }
     672             : } // end of anonymous namespace
     673             : 
     674             : //////////////////////////////////////////////////////////////////////////////
     675             : // primitive decomposition
     676             : 
     677           0 : void SdrTextObj::impDecomposePathTextPrimitive(
     678             :     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     679             :     const drawinglayer::primitive2d::SdrPathTextPrimitive2D& rSdrPathTextPrimitive,
     680             :     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
     681             : {
     682           0 :     drawinglayer::primitive2d::Primitive2DSequence aRetvalA;
     683           0 :     drawinglayer::primitive2d::Primitive2DSequence aRetvalB;
     684             : 
     685             :     // prepare outliner
     686           0 :     SdrOutliner& rOutliner = ImpGetDrawOutliner();
     687           0 :     rOutliner.SetUpdateMode(true);
     688           0 :     rOutliner.Clear();
     689           0 :     rOutliner.SetPaperSize(Size(LONG_MAX,LONG_MAX));
     690           0 :     rOutliner.SetText(rSdrPathTextPrimitive.getOutlinerParaObject());
     691             : 
     692             :     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
     693           0 :     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
     694             : 
     695             :     // now break up to text portions
     696           0 :     impTextBreakupHandler aConverter(rOutliner);
     697           0 :     const ::std::vector< impPathTextPortion > rPathTextPortions = aConverter.decompositionPathTextPrimitive();
     698             : 
     699           0 :     if(!rPathTextPortions.empty())
     700             :     {
     701             :         // get FormText and polygon values
     702           0 :         const drawinglayer::attribute::SdrFormTextAttribute& rFormTextAttribute = rSdrPathTextPrimitive.getSdrFormTextAttribute();
     703           0 :         const basegfx::B2DPolyPolygon& rPathPolyPolygon(rSdrPathTextPrimitive.getPathPolyPolygon());
     704             : 
     705             :         // get loop count
     706           0 :         sal_uInt32 nLoopCount(rPathPolyPolygon.count());
     707             : 
     708           0 :         if(rOutliner.GetParagraphCount() < nLoopCount)
     709             :         {
     710           0 :             nLoopCount = rOutliner.GetParagraphCount();
     711             :         }
     712             : 
     713           0 :         if(nLoopCount)
     714             :         {
     715             :             // prepare common decomposition stuff
     716           0 :             std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aRegularDecomposition;
     717           0 :             std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aShadowDecomposition;
     718             :             impPolygonParagraphHandler aPolygonParagraphHandler(
     719             :                 rFormTextAttribute,
     720             :                 aRegularDecomposition,
     721           0 :                 aShadowDecomposition);
     722             :             sal_uInt32 a;
     723             : 
     724           0 :             for(a = 0L; a < nLoopCount; a++)
     725             :             {
     726             :                 // filter text portions for this paragraph
     727           0 :                 ::std::vector< const impPathTextPortion* > aParagraphTextPortions;
     728             : 
     729           0 :                 for(sal_uInt32 b(0L); b < rPathTextPortions.size(); b++)
     730             :                 {
     731           0 :                     const impPathTextPortion& rCandidate = rPathTextPortions[b];
     732             : 
     733           0 :                     if(rCandidate.getParagraph() == a)
     734             :                     {
     735           0 :                         aParagraphTextPortions.push_back(&rCandidate);
     736             :                     }
     737             :                 }
     738             : 
     739             :                 // handle data pair polygon/ParagraphTextPortions
     740           0 :                 if(!aParagraphTextPortions.empty())
     741             :                 {
     742           0 :                     aPolygonParagraphHandler.HandlePair(rPathPolyPolygon.getB2DPolygon(a), aParagraphTextPortions);
     743             :                 }
     744           0 :             }
     745             : 
     746           0 :             const sal_uInt32 nShadowCount(aShadowDecomposition.size());
     747           0 :             const sal_uInt32 nRegularCount(aRegularDecomposition.size());
     748             : 
     749           0 :             if(nShadowCount)
     750             :             {
     751             :                 // add shadow primitives to decomposition
     752           0 :                 aRetvalA.realloc(nShadowCount);
     753             : 
     754           0 :                 for(a = 0L; a < nShadowCount; a++)
     755             :                 {
     756           0 :                     aRetvalA[a] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition[a]);
     757             :                 }
     758             : 
     759             :                 // if necessary, add shadow outlines
     760           0 :                 if(rFormTextAttribute.getFormTextOutline()
     761           0 :                     && !rFormTextAttribute.getShadowOutline().isDefault())
     762             :                 {
     763             :                     const drawinglayer::primitive2d::Primitive2DSequence aOutlines(
     764             :                         impAddPathTextOutlines(
     765             :                             aShadowDecomposition,
     766           0 :                             rFormTextAttribute.getShadowOutline()));
     767             : 
     768           0 :                     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA, aOutlines);
     769             :                 }
     770             :             }
     771             : 
     772           0 :             if(nRegularCount)
     773             :             {
     774             :                 // add normal primitives to decomposition
     775           0 :                 aRetvalB.realloc(nRegularCount);
     776             : 
     777           0 :                 for(a = 0L; a < nRegularCount; a++)
     778             :                 {
     779           0 :                     aRetvalB[a] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition[a]);
     780             :                 }
     781             : 
     782             :                 // if necessary, add outlines
     783           0 :                 if(rFormTextAttribute.getFormTextOutline()
     784           0 :                     && !rFormTextAttribute.getOutline().isDefault())
     785             :                 {
     786             :                     const drawinglayer::primitive2d::Primitive2DSequence aOutlines(
     787             :                         impAddPathTextOutlines(
     788             :                             aRegularDecomposition,
     789           0 :                             rFormTextAttribute.getOutline()));
     790             : 
     791           0 :                     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB, aOutlines);
     792             :                 }
     793           0 :             }
     794             :         }
     795             :     }
     796             : 
     797             :     // clean up outliner
     798           0 :     rOutliner.SetDrawPortionHdl(Link());
     799           0 :     rOutliner.Clear();
     800           0 :     rOutliner.setVisualizedPage(0);
     801             : 
     802             :     // concatenate all results
     803           0 :     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalA);
     804           0 :     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalB);
     805           0 : }
     806             : 
     807             : 
     808             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10