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

Generated by: LCOV version 1.11