LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/primitive2d - metafileprimitive2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 303 1163 26.1 %
Date: 2012-12-27 Functions: 75 98 76.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             : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
      21             : #include <basegfx/tools/canvastools.hxx>
      22             : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
      23             : #include <basegfx/color/bcolor.hxx>
      24             : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
      25             : #include <vcl/lineinfo.hxx>
      26             : #include <drawinglayer/attribute/lineattribute.hxx>
      27             : #include <drawinglayer/attribute/strokeattribute.hxx>
      28             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      29             : #include <vcl/metaact.hxx>
      30             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      31             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      32             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      33             : #include <basegfx/polygon/b2dpolygontools.hxx>
      34             : #include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
      35             : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
      36             : #include <vcl/salbtype.hxx>
      37             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      38             : #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
      39             : #include <vcl/svapp.hxx>
      40             : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
      41             : #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
      42             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      43             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      44             : #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
      45             : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
      46             : #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
      47             : #include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx>
      48             : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
      49             : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
      50             : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
      51             : #include <i18npool/languagetag.hxx>
      52             : #include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
      53             : #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
      54             : #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
      55             : #include <numeric>
      56             : 
      57             : //////////////////////////////////////////////////////////////////////////////
      58             : 
      59             : using namespace com::sun::star;
      60             : 
      61             : //////////////////////////////////////////////////////////////////////////////
      62             : 
      63             : namespace
      64             : {
      65             :     /** helper class for graphic context
      66             : 
      67             :         This class allows to hold a complete status of classic
      68             :         VCL OutputDevice stati. This data is needed for correct
      69             :         interpretation of the MetaFile action flow.
      70             :     */
      71          20 :     class PropertyHolder
      72             :     {
      73             :     private:
      74             :         /// current transformation (aka MapMode)
      75             :         basegfx::B2DHomMatrix   maTransformation;
      76             :         MapUnit                 maMapUnit;
      77             : 
      78             :         /// current colors
      79             :         basegfx::BColor         maLineColor;
      80             :         basegfx::BColor         maFillColor;
      81             :         basegfx::BColor         maTextColor;
      82             :         basegfx::BColor         maTextFillColor;
      83             :         basegfx::BColor         maTextLineColor;
      84             :         basegfx::BColor         maOverlineColor;
      85             : 
      86             :         /// clipping
      87             :         basegfx::B2DPolyPolygon maClipPolyPoygon;
      88             : 
      89             :         /// font, etc.
      90             :         Font                    maFont;
      91             :         RasterOp                maRasterOp;
      92             :         sal_uInt32              mnLayoutMode;
      93             :         LanguageType            maLanguageType;
      94             :         sal_uInt16              mnPushFlags;
      95             : 
      96             :         /// bitfield
      97             :         /// contains all active markers
      98             :         bool                    mbLineColor : 1;
      99             :         bool                    mbFillColor : 1;
     100             :         bool                    mbTextColor : 1;
     101             :         bool                    mbTextFillColor : 1;
     102             :         bool                    mbTextLineColor : 1;
     103             :         bool                    mbOverlineColor : 1;
     104             :         bool                    mbClipPolyPolygonActive : 1;
     105             : 
     106             :     public:
     107           2 :         PropertyHolder()
     108             :         :   maTransformation(),
     109             :             maMapUnit(MAP_100TH_MM),
     110             :             maLineColor(),
     111             :             maFillColor(),
     112             :             maTextColor(COL_BLACK),
     113             :             maTextFillColor(),
     114             :             maTextLineColor(),
     115             :             maOverlineColor(),
     116             :             maClipPolyPoygon(),
     117             :             maFont(),
     118             :             maRasterOp(ROP_OVERPAINT),
     119             :             mnLayoutMode(0),
     120             :             maLanguageType(0),
     121             :             mnPushFlags(0),
     122             :             mbLineColor(false),
     123             :             mbFillColor(false),
     124             :             mbTextColor(true),
     125             :             mbTextFillColor(false),
     126             :             mbTextLineColor(false),
     127             :             mbOverlineColor(false),
     128           2 :             mbClipPolyPolygonActive(false)
     129             :         {
     130           2 :         }
     131             : 
     132          22 :         ~PropertyHolder()
     133          22 :         {
     134          22 :         }
     135             : 
     136             :         /// read/write accesses
     137          43 :         const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; }
     138          20 :         void setTransformation(const basegfx::B2DHomMatrix& rNew) { if(rNew != maTransformation) maTransformation = rNew; }
     139             : 
     140          20 :         MapUnit getMapUnit() const { return maMapUnit; }
     141          21 :         void setMapUnit(MapUnit eNew) { if(eNew != maMapUnit) maMapUnit = eNew; }
     142             : 
     143           9 :         const basegfx::BColor& getLineColor() const { return maLineColor; }
     144           9 :         void setLineColor(const basegfx::BColor& rNew) { if(rNew != maLineColor) maLineColor = rNew; }
     145          26 :         bool getLineColorActive() const { return mbLineColor; }
     146          21 :         void setLineColorActive(bool bNew) { if(bNew != mbLineColor) mbLineColor = bNew; }
     147             : 
     148          37 :         const basegfx::BColor& getFillColor() const { return maFillColor; }
     149          27 :         void setFillColor(const basegfx::BColor& rNew) { if(rNew != maFillColor) maFillColor = rNew; }
     150          37 :         bool getFillColorActive() const { return mbFillColor; }
     151          27 :         void setFillColorActive(bool bNew) { if(bNew != mbFillColor) mbFillColor = bNew; }
     152             : 
     153          20 :         const basegfx::BColor& getTextColor() const { return maTextColor; }
     154          20 :         void setTextColor(const basegfx::BColor& rNew) { if(rNew != maTextColor) maTextColor = rNew; }
     155          20 :         bool getTextColorActive() const { return mbTextColor; }
     156          20 :         void setTextColorActive(bool bNew) { if(bNew != mbTextColor) mbTextColor = bNew; }
     157             : 
     158          20 :         const basegfx::BColor& getTextFillColor() const { return maTextFillColor; }
     159          20 :         void setTextFillColor(const basegfx::BColor& rNew) { if(rNew != maTextFillColor) maTextFillColor = rNew; }
     160          20 :         bool getTextFillColorActive() const { return mbTextFillColor; }
     161          20 :         void setTextFillColorActive(bool bNew) { if(bNew != mbTextFillColor) mbTextFillColor = bNew; }
     162             : 
     163          20 :         const basegfx::BColor& getTextLineColor() const { return maTextLineColor; }
     164          20 :         void setTextLineColor(const basegfx::BColor& rNew) { if(rNew != maTextLineColor) maTextLineColor = rNew; }
     165          20 :         bool getTextLineColorActive() const { return mbTextLineColor; }
     166          20 :         void setTextLineColorActive(bool bNew) { if(bNew != mbTextLineColor) mbTextLineColor = bNew; }
     167             : 
     168          20 :         const basegfx::BColor& getOverlineColor() const { return maOverlineColor; }
     169          20 :         void setOverlineColor(const basegfx::BColor& rNew) { if(rNew != maOverlineColor) maOverlineColor = rNew; }
     170          20 :         bool getOverlineColorActive() const { return mbOverlineColor; }
     171          20 :         void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; }
     172             : 
     173          18 :         const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; }
     174          16 :         void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; }
     175          67 :         bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; }
     176          21 :         void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; }
     177             : 
     178          60 :         const Font& getFont() const { return maFont; }
     179          20 :         void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; }
     180             : 
     181          20 :         const RasterOp& getRasterOp() const { return maRasterOp; }
     182          29 :         void setRasterOp(const RasterOp& rRasterOp) { if(rRasterOp != maRasterOp) maRasterOp = rRasterOp; }
     183          18 :         bool isRasterOpInvert() const { return (ROP_XOR == maRasterOp || ROP_INVERT == maRasterOp); }
     184          18 :         bool isRasterOpForceBlack() const { return ROP_0 == maRasterOp; }
     185          18 :         bool isRasterOpActive() const { return isRasterOpInvert() || isRasterOpForceBlack(); }
     186             : 
     187          20 :         sal_uInt32 getLayoutMode() const { return mnLayoutMode; }
     188          20 :         void setLayoutMode(sal_uInt32 nNew) { if(nNew != mnLayoutMode) mnLayoutMode = nNew; }
     189             : 
     190          20 :         LanguageType getLanguageType() const { return maLanguageType; }
     191          20 :         void setLanguageType(LanguageType aNew) { if(aNew != maLanguageType) maLanguageType = aNew; }
     192             : 
     193          60 :         sal_uInt16 getPushFlags() const { return mnPushFlags; }
     194          20 :         void setPushFlags(sal_uInt16 nNew) { if(nNew != mnPushFlags) mnPushFlags = nNew; }
     195             : 
     196          17 :         bool getLineOrFillActive() const { return (mbLineColor || mbFillColor); }
     197             :     };
     198             : } // end of anonymous namespace
     199             : 
     200             : //////////////////////////////////////////////////////////////////////////////
     201             : 
     202             : namespace
     203             : {
     204             :     /** stack for properites
     205             : 
     206             :         This class builds a stack based on the PropertyHolder
     207             :         class. It encapsulates the pointer/new/delete usage to
     208             :         make it safe and implements the push/pop as needed by a
     209             :         VCL Metafile interpreter. The critical part here are the
     210             :         flag values VCL OutputDevice uses here; not all stuff is
     211             :         pushed and thus needs to be copied at pop.
     212             :     */
     213             :     class PropertyHolders
     214             :     {
     215             :     private:
     216             :         std::vector< PropertyHolder* >          maPropertyHolders;
     217             : 
     218             :     public:
     219           1 :         PropertyHolders()
     220           1 :         {
     221           1 :             maPropertyHolders.push_back(new PropertyHolder());
     222           1 :         }
     223             : 
     224             :         sal_uInt32 size() const
     225             :         {
     226             :             return maPropertyHolders.size();
     227             :         }
     228             : 
     229           0 :         void PushDefault()
     230             :         {
     231           0 :             PropertyHolder* pNew = new PropertyHolder();
     232           0 :             maPropertyHolders.push_back(pNew);
     233           0 :         }
     234             : 
     235          20 :         void Push(sal_uInt16 nPushFlags)
     236             :         {
     237          20 :             if(nPushFlags)
     238             :             {
     239             :                 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)");
     240          20 :                 if ( !maPropertyHolders.empty() )
     241             :                 {
     242          20 :                     PropertyHolder* pNew = new PropertyHolder(*maPropertyHolders.back());
     243          20 :                     pNew->setPushFlags(nPushFlags);
     244          20 :                     maPropertyHolders.push_back(pNew);
     245             :                 }
     246             :             }
     247          20 :         }
     248             : 
     249          20 :         void Pop()
     250             :         {
     251             :             OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)");
     252          20 :             const sal_uInt32 nSize(maPropertyHolders.size());
     253             : 
     254          20 :             if(nSize)
     255             :             {
     256          20 :                 const PropertyHolder* pTip = maPropertyHolders.back();
     257          20 :                 const sal_uInt16 nPushFlags(pTip->getPushFlags());
     258             : 
     259          20 :                 if(nPushFlags)
     260             :                 {
     261          20 :                     if(nSize > 1)
     262             :                     {
     263             :                         // copy back content for all non-set flags
     264          20 :                         PropertyHolder* pLast = maPropertyHolders[nSize - 2];
     265             : 
     266          20 :                         if(PUSH_ALL != nPushFlags)
     267             :                         {
     268          20 :                             if(!(nPushFlags & PUSH_LINECOLOR      ))
     269             :                             {
     270           9 :                                 pLast->setLineColor(pTip->getLineColor());
     271           9 :                                 pLast->setLineColorActive(pTip->getLineColorActive());
     272             :                             }
     273          20 :                             if(!(nPushFlags & PUSH_FILLCOLOR      ))
     274             :                             {
     275          20 :                                 pLast->setFillColor(pTip->getFillColor());
     276          20 :                                 pLast->setFillColorActive(pTip->getFillColorActive());
     277             :                             }
     278          20 :                             if(!(nPushFlags & PUSH_FONT           ))
     279             :                             {
     280          20 :                                 pLast->setFont(pTip->getFont());
     281             :                             }
     282          20 :                             if(!(nPushFlags & PUSH_TEXTCOLOR      ))
     283             :                             {
     284          20 :                                 pLast->setTextColor(pTip->getTextColor());
     285          20 :                                 pLast->setTextColorActive(pTip->getTextColorActive());
     286             :                             }
     287          20 :                             if(!(nPushFlags & PUSH_MAPMODE        ))
     288             :                             {
     289          20 :                                 pLast->setTransformation(pTip->getTransformation());
     290          20 :                                 pLast->setMapUnit(pTip->getMapUnit());
     291             :                             }
     292          20 :                             if(!(nPushFlags & PUSH_CLIPREGION     ))
     293             :                             {
     294          11 :                                 pLast->setClipPolyPolygon(pTip->getClipPolyPolygon());
     295          11 :                                 pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive());
     296             :                             }
     297          20 :                             if(!(nPushFlags & PUSH_RASTEROP       ))
     298             :                             {
     299          20 :                                 pLast->setRasterOp(pTip->getRasterOp());
     300             :                             }
     301          20 :                             if(!(nPushFlags & PUSH_TEXTFILLCOLOR  ))
     302             :                             {
     303          20 :                                 pLast->setTextFillColor(pTip->getTextFillColor());
     304          20 :                                 pLast->setTextFillColorActive(pTip->getTextFillColorActive());
     305             :                             }
     306          20 :                             if(!(nPushFlags & PUSH_TEXTALIGN      ))
     307             :                             {
     308          20 :                                 if(pLast->getFont().GetAlign() != pTip->getFont().GetAlign())
     309             :                                 {
     310           0 :                                     Font aFont(pLast->getFont());
     311           0 :                                     aFont.SetAlign(pTip->getFont().GetAlign());
     312           0 :                                     pLast->setFont(aFont);
     313             :                                 }
     314             :                             }
     315          20 :                             if(!(nPushFlags & PUSH_REFPOINT       ))
     316             :                             {
     317             :                                 // not supported
     318             :                             }
     319          20 :                             if(!(nPushFlags & PUSH_TEXTLINECOLOR  ))
     320             :                             {
     321          20 :                                 pLast->setTextLineColor(pTip->getTextLineColor());
     322          20 :                                 pLast->setTextLineColorActive(pTip->getTextLineColorActive());
     323             :                             }
     324          20 :                             if(!(nPushFlags & PUSH_TEXTLAYOUTMODE ))
     325             :                             {
     326          20 :                                 pLast->setLayoutMode(pTip->getLayoutMode());
     327             :                             }
     328          20 :                             if(!(nPushFlags & PUSH_TEXTLANGUAGE   ))
     329             :                             {
     330          20 :                                 pLast->setLanguageType(pTip->getLanguageType());
     331             :                             }
     332          20 :                             if(!(nPushFlags & PUSH_OVERLINECOLOR  ))
     333             :                             {
     334          20 :                                 pLast->setOverlineColor(pTip->getOverlineColor());
     335          20 :                                 pLast->setOverlineColorActive(pTip->getOverlineColorActive());
     336             :                             }
     337             :                         }
     338             :                     }
     339             :                 }
     340             : 
     341             :                 // execute the pop
     342          20 :                 delete maPropertyHolders.back();
     343          20 :                 maPropertyHolders.pop_back();
     344             :             }
     345          20 :         }
     346             : 
     347         210 :         PropertyHolder& Current()
     348             :         {
     349         210 :             static PropertyHolder aDummy;
     350             :             OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)");
     351         210 :             return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back();
     352             :         }
     353             : 
     354           1 :         ~PropertyHolders()
     355           1 :         {
     356           3 :             while(!maPropertyHolders.empty())
     357             :             {
     358           1 :                 delete maPropertyHolders.back();
     359           1 :                 maPropertyHolders.pop_back();
     360             :             }
     361           1 :         }
     362             :     };
     363             : } // end of anonymous namespace
     364             : 
     365             : //////////////////////////////////////////////////////////////////////////////
     366             : 
     367             : namespace
     368             : {
     369             :     /** helper to convert a Region to a B2DPolyPolygon
     370             :         when it does not yet contain one. In the future
     371             :         this may be expanded to merge the polygons created
     372             :         from rectangles or use a special algo to directly turn
     373             :         the spans of regions to a single, already merged
     374             :         PolyPolygon.
     375             :      */
     376           0 :     basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const Region& rRegion)
     377             :     {
     378           0 :         basegfx::B2DPolyPolygon aRetval;
     379             : 
     380           0 :         if(!rRegion.IsEmpty())
     381             :         {
     382           0 :             Region aRegion(rRegion);
     383           0 :             aRetval = aRegion.GetB2DPolyPolygon();
     384             : 
     385           0 :             if(!aRetval.count())
     386             :             {
     387           0 :                 RegionHandle aRegionHandle(aRegion.BeginEnumRects());
     388           0 :                 Rectangle aRegionRectangle;
     389             : 
     390           0 :                 while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle))
     391             :                 {
     392           0 :                     if(!aRegionRectangle.IsEmpty())
     393             :                     {
     394             :                         const basegfx::B2DRange aRegionRange(
     395           0 :                             aRegionRectangle.Left(), aRegionRectangle.Top(),
     396           0 :                             aRegionRectangle.Right(), aRegionRectangle.Bottom());
     397           0 :                         aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange));
     398             :                     }
     399             :                 }
     400             : 
     401           0 :                 aRegion.EndEnumRects(aRegionHandle);
     402           0 :             }
     403             :         }
     404             : 
     405           0 :         return aRetval;
     406             :     }
     407             : } // end of anonymous namespace
     408             : 
     409             : //////////////////////////////////////////////////////////////////////////////
     410             : 
     411             : namespace
     412             : {
     413             :     /** Helper class to buffer and hold a Primive target vector. It
     414             :         encapsulates the new/delete functionality and aloows to work
     415             :         on pointers of the implementation classes. All data will
     416             :         be converted to uno sequences of uno references when accessing the
     417             :         data.
     418             :     */
     419             :     class TargetHolder
     420             :     {
     421             :     private:
     422             :         std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargets;
     423             : 
     424             :     public:
     425           6 :         TargetHolder()
     426           6 :         :   aTargets()
     427             :         {
     428           6 :         }
     429             : 
     430           6 :         ~TargetHolder()
     431           6 :         {
     432           6 :             const sal_uInt32 nCount(aTargets.size());
     433             : 
     434           6 :             for(sal_uInt32 a(0); a < nCount; a++)
     435             :             {
     436           0 :                 delete aTargets[a];
     437             :             }
     438           6 :         }
     439             : 
     440           5 :         sal_uInt32 size() const
     441             :         {
     442           5 :             return aTargets.size();
     443             :         }
     444             : 
     445          20 :         void append(drawinglayer::primitive2d::BasePrimitive2D* pCandidate)
     446             :         {
     447          20 :             if(pCandidate)
     448             :             {
     449          20 :                 aTargets.push_back(pCandidate);
     450             :             }
     451          20 :         }
     452             : 
     453           3 :         drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence(const PropertyHolder& rPropertyHolder)
     454             :         {
     455           3 :             const sal_uInt32 nCount(aTargets.size());
     456           3 :             drawinglayer::primitive2d::Primitive2DSequence xRetval(nCount);
     457             : 
     458          23 :             for(sal_uInt32 a(0); a < nCount; a++)
     459             :             {
     460          20 :                 xRetval[a] = aTargets[a];
     461             :             }
     462             : 
     463             :             // All Targets were pointers, but do not need to be deleted since they
     464             :             // were converted to UNO API references now, so they stay as long as
     465             :             // referenced. Do NOT delete the C++ implementation classes here, but clear
     466             :             // the buffer to not delete them in the destructor.
     467           3 :             aTargets.clear();
     468             : 
     469           3 :             if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive())
     470             :             {
     471           2 :                 const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon();
     472             : 
     473           2 :                 if(rClipPolyPolygon.count())
     474             :                 {
     475             :                     const drawinglayer::primitive2d::Primitive2DReference xMask(
     476             :                         new drawinglayer::primitive2d::MaskPrimitive2D(
     477             :                             rClipPolyPolygon,
     478           2 :                             xRetval));
     479             : 
     480           2 :                     xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
     481             :                 }
     482             :             }
     483             : 
     484           3 :             return xRetval;
     485             :         }
     486             :     };
     487             : } // end of anonymous namespace
     488             : 
     489             : //////////////////////////////////////////////////////////////////////////////
     490             : 
     491             : namespace
     492             : {
     493             :     /** Helper class which builds a stack on the TargetHolder class */
     494             :     class TargetHolders
     495             :     {
     496             :     private:
     497             :         std::vector< TargetHolder* >          maTargetHolders;
     498             : 
     499             :     public:
     500           1 :         TargetHolders()
     501           1 :         {
     502           1 :             maTargetHolders.push_back(new TargetHolder());
     503           1 :         }
     504             : 
     505           6 :         sal_uInt32 size() const
     506             :         {
     507           6 :             return maTargetHolders.size();
     508             :         }
     509             : 
     510           5 :         void Push()
     511             :         {
     512           5 :             maTargetHolders.push_back(new TargetHolder());
     513           5 :         }
     514             : 
     515           5 :         void Pop()
     516             :         {
     517             :             OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)");
     518           5 :             if(!maTargetHolders.empty())
     519             :             {
     520           5 :                 delete maTargetHolders.back();
     521           5 :                 maTargetHolders.pop_back();
     522             :             }
     523           5 :         }
     524             : 
     525          28 :         TargetHolder& Current()
     526             :         {
     527             :             OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)");
     528          28 :             return *maTargetHolders.back();
     529             :         }
     530             : 
     531           1 :         ~TargetHolders()
     532           1 :         {
     533           3 :             while(!maTargetHolders.empty())
     534             :             {
     535           1 :                 delete maTargetHolders.back();
     536           1 :                 maTargetHolders.pop_back();
     537             :             }
     538           1 :         }
     539             :     };
     540             : } // end of anonymous namespace
     541             : 
     542             : //////////////////////////////////////////////////////////////////////////////
     543             : 
     544             : namespace drawinglayer
     545             : {
     546             :     namespace primitive2d
     547             :     {
     548             :         /** NonOverlappingFillGradientPrimitive2D class
     549             : 
     550             :             This is a special version of the FillGradientPrimitive2D which decomposes
     551             :             to a non-overlapping geometry version of the gradient. This needs to be
     552             :             used to support the old XOR paint-'trick'.
     553             : 
     554             :             It does not need an own identifier since a renderer who wants to interpret
     555             :             it itself may do so. It just overloads the decomposition of the C++
     556             :             implementation class to do an alternative decomposition.
     557             :          */
     558           0 :         class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D
     559             :         {
     560             :         protected:
     561             :             /// local decomposition.
     562             :             virtual Primitive2DSequence create2DDecomposition(
     563             :                 const geometry::ViewInformation2D& rViewInformation) const;
     564             : 
     565             :         public:
     566             :             /// constructor
     567           0 :             NonOverlappingFillGradientPrimitive2D(
     568             :                 const basegfx::B2DRange& rObjectRange,
     569             :                 const attribute::FillGradientAttribute& rFillGradient)
     570           0 :             :   FillGradientPrimitive2D(rObjectRange, rFillGradient)
     571             :             {
     572           0 :             }
     573             :         };
     574             : 
     575           0 :         Primitive2DSequence NonOverlappingFillGradientPrimitive2D::create2DDecomposition(
     576             :             const geometry::ViewInformation2D& /*rViewInformation*/) const
     577             :         {
     578           0 :             if(!getFillGradient().isDefault())
     579             :             {
     580           0 :                 return createFill(false);
     581             :             }
     582             :             else
     583             :             {
     584           0 :                 return Primitive2DSequence();
     585             :             }
     586             :         }
     587             :     } // end of namespace primitive2d
     588             : } // end of namespace drawinglayer
     589             : 
     590             : //////////////////////////////////////////////////////////////////////////////
     591             : 
     592             : namespace
     593             : {
     594             :     /** helper to convert a MapMode to a transformation */
     595           0 :     basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
     596             :     {
     597           0 :         basegfx::B2DHomMatrix aMapping;
     598           0 :         const Fraction aNoScale(1, 1);
     599           0 :         const Point& rOrigin(rMapMode.GetOrigin());
     600             : 
     601           0 :         if(0 != rOrigin.X() || 0 != rOrigin.Y())
     602             :         {
     603           0 :             aMapping.translate(rOrigin.X(), rOrigin.Y());
     604             :         }
     605             : 
     606           0 :         if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
     607             :         {
     608             :             aMapping.scale(
     609           0 :                 double(rMapMode.GetScaleX()),
     610           0 :                 double(rMapMode.GetScaleY()));
     611             :         }
     612             : 
     613           0 :         return aMapping;
     614             :     }
     615             : 
     616             :     /** helper to create a PointArrayPrimitive2D based on current context */
     617           0 :     void createPointArrayPrimitive(
     618             :         const std::vector< basegfx::B2DPoint >& rPositions,
     619             :         TargetHolder& rTarget,
     620             :         PropertyHolder& rProperties,
     621             :         basegfx::BColor aBColor)
     622             :     {
     623           0 :         if(!rPositions.empty())
     624             :         {
     625           0 :             if(rProperties.getTransformation().isIdentity())
     626             :             {
     627             :                 rTarget.append(
     628             :                     new drawinglayer::primitive2d::PointArrayPrimitive2D(
     629             :                         rPositions,
     630           0 :                         aBColor));
     631             :             }
     632             :             else
     633             :             {
     634           0 :                 std::vector< basegfx::B2DPoint > aPositions(rPositions);
     635             : 
     636           0 :                 for(sal_uInt32 a(0); a < aPositions.size(); a++)
     637             :                 {
     638           0 :                     aPositions[a] = rProperties.getTransformation() * aPositions[a];
     639             :                 }
     640             : 
     641             :                 rTarget.append(
     642             :                     new drawinglayer::primitive2d::PointArrayPrimitive2D(
     643             :                         aPositions,
     644           0 :                         aBColor));
     645             :             }
     646             :         }
     647           0 :     }
     648             : 
     649             :     /** helper to create a PolygonHairlinePrimitive2D based on current context */
     650           0 :     void createHairlinePrimitive(
     651             :         const basegfx::B2DPolygon& rLinePolygon,
     652             :         TargetHolder& rTarget,
     653             :         PropertyHolder& rProperties)
     654             :     {
     655           0 :         if(rLinePolygon.count())
     656             :         {
     657           0 :             basegfx::B2DPolygon aLinePolygon(rLinePolygon);
     658           0 :             aLinePolygon.transform(rProperties.getTransformation());
     659             :             rTarget.append(
     660             :                 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
     661             :                     aLinePolygon,
     662           0 :                     rProperties.getLineColor()));
     663             :         }
     664           0 :     }
     665             : 
     666             :     /** helper to create a PolyPolygonColorPrimitive2D based on current context */
     667          17 :     void createFillPrimitive(
     668             :         const basegfx::B2DPolyPolygon& rFillPolyPolygon,
     669             :         TargetHolder& rTarget,
     670             :         PropertyHolder& rProperties)
     671             :     {
     672          17 :         if(rFillPolyPolygon.count())
     673             :         {
     674          17 :             basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon);
     675          17 :             aFillPolyPolygon.transform(rProperties.getTransformation());
     676             :             rTarget.append(
     677             :                 new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
     678             :                     aFillPolyPolygon,
     679          17 :                     rProperties.getFillColor()));
     680             :         }
     681          17 :     }
     682             : 
     683             :     /** helper to create a PolygonStrokePrimitive2D based on current context */
     684           0 :     void createLinePrimitive(
     685             :         const basegfx::B2DPolygon& rLinePolygon,
     686             :         const LineInfo& rLineInfo,
     687             :         TargetHolder& rTarget,
     688             :         PropertyHolder& rProperties)
     689             :     {
     690           0 :         if(rLinePolygon.count())
     691             :         {
     692           0 :             const bool bDashDotUsed(LINE_DASH == rLineInfo.GetStyle());
     693           0 :             const bool bWidthUsed(rLineInfo.GetWidth() > 1);
     694             : 
     695           0 :             if(bDashDotUsed || bWidthUsed)
     696             :             {
     697           0 :                 basegfx::B2DPolygon aLinePolygon(rLinePolygon);
     698           0 :                 aLinePolygon.transform(rProperties.getTransformation());
     699             :                 const drawinglayer::attribute::LineAttribute aLineAttribute(
     700           0 :                     rProperties.getLineColor(),
     701           0 :                     bWidthUsed ? rLineInfo.GetWidth() : 0.0,
     702             :                     rLineInfo.GetLineJoin(),
     703           0 :                     rLineInfo.GetLineCap());
     704             : 
     705           0 :                 if(bDashDotUsed)
     706             :                 {
     707           0 :                     ::std::vector< double > fDotDashArray;
     708           0 :                     const double fDashLen(rLineInfo.GetDashLen());
     709           0 :                     const double fDotLen(rLineInfo.GetDotLen());
     710           0 :                     const double fDistance(rLineInfo.GetDistance());
     711             : 
     712           0 :                     for(sal_uInt16 a(0); a < rLineInfo.GetDashCount(); a++)
     713             :                     {
     714           0 :                         fDotDashArray.push_back(fDashLen);
     715           0 :                         fDotDashArray.push_back(fDistance);
     716             :                     }
     717             : 
     718           0 :                     for(sal_uInt16 b(0); b < rLineInfo.GetDotCount(); b++)
     719             :                     {
     720           0 :                         fDotDashArray.push_back(fDotLen);
     721           0 :                         fDotDashArray.push_back(fDistance);
     722             :                     }
     723             : 
     724           0 :                     const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
     725             :                     const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
     726             :                         fDotDashArray,
     727           0 :                         fAccumulated);
     728             : 
     729             :                     rTarget.append(
     730             :                         new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
     731             :                             aLinePolygon,
     732             :                             aLineAttribute,
     733           0 :                             aStrokeAttribute));
     734             :                 }
     735             :                 else
     736             :                 {
     737             :                     rTarget.append(
     738             :                         new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
     739             :                             aLinePolygon,
     740           0 :                             aLineAttribute));
     741           0 :                 }
     742             :             }
     743             :             else
     744             :             {
     745           0 :                 createHairlinePrimitive(rLinePolygon, rTarget, rProperties);
     746             :             }
     747             :         }
     748           0 :     }
     749             : 
     750             :     /** helper to create needed line and fill primitives based on current context */
     751           6 :     void createHairlineAndFillPrimitive(
     752             :         const basegfx::B2DPolygon& rPolygon,
     753             :         TargetHolder& rTarget,
     754             :         PropertyHolder& rProperties)
     755             :     {
     756           6 :         if(rProperties.getFillColorActive())
     757             :         {
     758           6 :             createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties);
     759             :         }
     760             : 
     761           6 :         if(rProperties.getLineColorActive())
     762             :         {
     763           0 :             createHairlinePrimitive(rPolygon, rTarget, rProperties);
     764             :         }
     765           6 :     }
     766             : 
     767             :     /** helper to create needed line and fill primitives based on current context */
     768          11 :     void createHairlineAndFillPrimitive(
     769             :         const basegfx::B2DPolyPolygon& rPolyPolygon,
     770             :         TargetHolder& rTarget,
     771             :         PropertyHolder& rProperties)
     772             :     {
     773          11 :         if(rProperties.getFillColorActive())
     774             :         {
     775          11 :             createFillPrimitive(rPolyPolygon, rTarget, rProperties);
     776             :         }
     777             : 
     778          11 :         if(rProperties.getLineColorActive())
     779             :         {
     780           0 :             for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++)
     781             :             {
     782           0 :                 createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties);
     783             :             }
     784             :         }
     785          11 :     }
     786             : 
     787             :     /** helper to create DiscreteBitmapPrimitive2D based on current context.
     788             :         The DiscreteBitmapPrimitive2D is especially created for this usage
     789             :         since no other usage defines a bitmap visualisation based on top-left
     790             :         position and size in pixels. At the end it will create a view-dependent
     791             :         transformed embedding of a BitmapPrimitive2D.
     792             :     */
     793           0 :     void createBitmapExPrimitive(
     794             :         const BitmapEx& rBitmapEx,
     795             :         const Point& rPoint,
     796             :         TargetHolder& rTarget,
     797             :         PropertyHolder& rProperties)
     798             :     {
     799           0 :         if(!rBitmapEx.IsEmpty())
     800             :         {
     801           0 :             basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y());
     802           0 :             aPoint = rProperties.getTransformation() * aPoint;
     803             : 
     804             :             rTarget.append(
     805             :                 new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
     806             :                     rBitmapEx,
     807           0 :                     aPoint));
     808             :         }
     809           0 :     }
     810             : 
     811             :     /** helper to create BitmapPrimitive2D based on current context */
     812           1 :     void createBitmapExPrimitive(
     813             :         const BitmapEx& rBitmapEx,
     814             :         const Point& rPoint,
     815             :         const Size& rSize,
     816             :         TargetHolder& rTarget,
     817             :         PropertyHolder& rProperties)
     818             :     {
     819           1 :         if(!rBitmapEx.IsEmpty())
     820             :         {
     821           1 :             basegfx::B2DHomMatrix aObjectTransform;
     822             : 
     823           1 :             aObjectTransform.set(0, 0, rSize.Width());
     824           1 :             aObjectTransform.set(1, 1, rSize.Height());
     825           1 :             aObjectTransform.set(0, 2, rPoint.X());
     826           1 :             aObjectTransform.set(1, 2, rPoint.Y());
     827             : 
     828           1 :             aObjectTransform = rProperties.getTransformation() * aObjectTransform;
     829             : 
     830             :             rTarget.append(
     831             :                 new drawinglayer::primitive2d::BitmapPrimitive2D(
     832             :                     rBitmapEx,
     833           1 :                     aObjectTransform));
     834             :         }
     835           1 :     }
     836             : 
     837             :     /** helper to create a regular BotmapEx from a MaskAction (definitions
     838             :         which use a bitmap without transparence but define one of the colors as
     839             :         transparent)
     840             :      */
     841           0 :     BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor)
     842             :     {
     843           0 :         const Color aWhite(COL_WHITE);
     844           0 :         BitmapPalette aBiLevelPalette(2);
     845             : 
     846           0 :         aBiLevelPalette[0] = aWhite;
     847           0 :         aBiLevelPalette[1] = rMaskColor;
     848             : 
     849           0 :         Bitmap aMask(rBitmap.CreateMask(aWhite));
     850           0 :         Bitmap aSolid(rBitmap.GetSizePixel(), 1, &aBiLevelPalette);
     851             : 
     852           0 :         aSolid.Erase(rMaskColor);
     853             : 
     854           0 :         return BitmapEx(aSolid, aMask);
     855             :     }
     856             : 
     857             :     /** helper to convert from a VCL Gradient definition to the corresponding
     858             :         data for primitive representation
     859             :      */
     860           0 :     drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient& rGradient)
     861             :     {
     862           0 :         const Color aStartColor(rGradient.GetStartColor());
     863           0 :         const sal_uInt16 nStartIntens(rGradient.GetStartIntensity());
     864           0 :         basegfx::BColor aStart(aStartColor.getBColor());
     865             : 
     866           0 :         if(nStartIntens != 100)
     867             :         {
     868           0 :             const basegfx::BColor aBlack;
     869           0 :             aStart = interpolate(aBlack, aStart, (double)nStartIntens * 0.01);
     870             :         }
     871             : 
     872           0 :         const Color aEndColor(rGradient.GetEndColor());
     873           0 :         const sal_uInt16 nEndIntens(rGradient.GetEndIntensity());
     874           0 :         basegfx::BColor aEnd(aEndColor.getBColor());
     875             : 
     876           0 :         if(nEndIntens != 100)
     877             :         {
     878           0 :             const basegfx::BColor aBlack;
     879           0 :             aEnd = interpolate(aBlack, aEnd, (double)nEndIntens * 0.01);
     880             :         }
     881             : 
     882           0 :         drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GRADIENTSTYLE_RECT);
     883             : 
     884           0 :         switch(rGradient.GetStyle())
     885             :         {
     886             :             case GradientStyle_LINEAR :
     887             :             {
     888           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_LINEAR;
     889           0 :                 break;
     890             :             }
     891             :             case GradientStyle_AXIAL :
     892             :             {
     893           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_AXIAL;
     894           0 :                 break;
     895             :             }
     896             :             case GradientStyle_RADIAL :
     897             :             {
     898           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RADIAL;
     899           0 :                 break;
     900             :             }
     901             :             case GradientStyle_ELLIPTICAL :
     902             :             {
     903           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_ELLIPTICAL;
     904           0 :                 break;
     905             :             }
     906             :             case GradientStyle_SQUARE :
     907             :             {
     908           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_SQUARE;
     909           0 :                 break;
     910             :             }
     911             :             default : // GradientStyle_RECT
     912             :             {
     913           0 :                 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RECT;
     914           0 :                 break;
     915             :             }
     916             :         }
     917             : 
     918             :         return drawinglayer::attribute::FillGradientAttribute(
     919             :             aGradientStyle,
     920           0 :             (double)rGradient.GetBorder() * 0.01,
     921           0 :             (double)rGradient.GetOfsX() * 0.01,
     922           0 :             (double)rGradient.GetOfsY() * 0.01,
     923           0 :             (double)rGradient.GetAngle() * F_PI1800,
     924             :             aStart,
     925             :             aEnd,
     926           0 :             rGradient.GetSteps());
     927             :     }
     928             : 
     929             :     /** helper to convert from a VCL Hatch definition to the corresponding
     930             :         data for primitive representation
     931             :      */
     932           0 :     drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch& rHatch)
     933             :     {
     934           0 :         drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HATCHSTYLE_SINGLE);
     935             : 
     936           0 :         switch(rHatch.GetStyle())
     937             :         {
     938             :             default : // case HATCH_SINGLE :
     939             :             {
     940           0 :                 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE;
     941           0 :                 break;
     942             :             }
     943             :             case HATCH_DOUBLE :
     944             :             {
     945           0 :                 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE;
     946           0 :                 break;
     947             :             }
     948             :             case HATCH_TRIPLE :
     949             :             {
     950           0 :                 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE;
     951           0 :                 break;
     952             :             }
     953             :         }
     954             : 
     955             :         return drawinglayer::attribute::FillHatchAttribute(
     956             :             aHatchStyle,
     957           0 :             (double)rHatch.GetDistance(),
     958           0 :             (double)rHatch.GetAngle() * F_PI1800,
     959           0 :             rHatch.GetColor().getBColor(),
     960           0 :             false);
     961             :     }
     962             : 
     963             :     /** helper to take needed action on ClipRegion change. This method needs to be called
     964             :         on any Region change, e.g. at the obvious actions doing this, but also at pop-calls
     965             :         whcih change the Region of the current context. It takes care of creating the
     966             :         current embeddec context, set the new Region at the context and eventually prepare
     967             :         a new target for embracing new geometry to the current region
     968             :      */
     969          10 :     void HandleNewClipRegion(
     970             :         const basegfx::B2DPolyPolygon& rClipPolyPolygon,
     971             :         TargetHolders& rTargetHolders,
     972             :         PropertyHolders& rPropertyHolders)
     973             :     {
     974          10 :         const bool bNewActive(rClipPolyPolygon.count());
     975             : 
     976             :         // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible
     977             :         // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set
     978             :         // initially and then using a lot of push/pop actions, the pop always leads
     979             :         // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon
     980             :         // of the properties next on the stack.
     981             :         //
     982             :         // This ClipPolyPolygon is identical to the current one, so there is no need to
     983             :         // create a MaskPrimitive2D containing the up-to-now created primitives, but
     984             :         // this was done before. While this does not lead to wrong primitive
     985             :         // representations of the metafile data, it creates unneccesarily expensive
     986             :         // representations. Just detecting when no really 'new' ClipPolyPolygon gets set
     987             :         // solves the problem.
     988             : 
     989          10 :         if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive)
     990             :         {
     991             :             // no active ClipPolyPolygon exchanged by no new one, done
     992           0 :             return;
     993             :         }
     994             : 
     995          10 :         if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive)
     996             :         {
     997             :             // active ClipPolyPolygon and new active ClipPolyPolygon
     998           0 :             if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon)
     999             :             {
    1000             :                 // new is the same as old, done
    1001           0 :                 return;
    1002             :             }
    1003             :         }
    1004             : 
    1005             :         // Here the old and the new are definitively different, maybe
    1006             :         // old one and/or new one is not active.
    1007             : 
    1008             :         // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which
    1009             :         // belong to this active ClipPolyPolygon. These need to be embedded to a
    1010             :         // MaskPrimitive2D accordingly.
    1011          10 :         if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1)
    1012             :         {
    1013           5 :             drawinglayer::primitive2d::Primitive2DSequence aSubContent;
    1014             : 
    1015          10 :             if(rPropertyHolders.Current().getClipPolyPolygon().count()
    1016           5 :                 && rTargetHolders.Current().size())
    1017             :             {
    1018           2 :                 aSubContent = rTargetHolders.Current().getPrimitive2DSequence(
    1019           4 :                     rPropertyHolders.Current());
    1020             :             }
    1021             : 
    1022           5 :             rTargetHolders.Pop();
    1023             : 
    1024           5 :             if(aSubContent.hasElements())
    1025             :             {
    1026           2 :                 rTargetHolders.Current().append(
    1027             :                     new drawinglayer::primitive2d::GroupPrimitive2D(
    1028           4 :                         aSubContent));
    1029           5 :             }
    1030             :         }
    1031             : 
    1032             :         // apply new settings to current properties by setting
    1033             :         // the new region now
    1034          10 :         rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive);
    1035             : 
    1036          10 :         if(bNewActive)
    1037             :         {
    1038           5 :             rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon);
    1039             : 
    1040             :             // prepare new content holder for new active region
    1041           5 :             rTargetHolders.Push();
    1042             :         }
    1043             :     }
    1044             : 
    1045             :     /** helper to handle the change of RasterOp. It takes care of encapsulating all current
    1046             :         geometry to the current RasterOp (if changed) and needs to be called on any RasterOp
    1047             :         change. It will also start a new geometry target to embrace to the new RasterOp if
    1048             :         a changuing RasterOp is used. Currently, ROP_XOR and ROP_INVERT are supported using
    1049             :         InvertPrimitive2D, and ROP_0 by using a ModifiedColorPrimitive2D to force to black paint
    1050             :      */
    1051           9 :     void HandleNewRasterOp(
    1052             :         RasterOp aRasterOp,
    1053             :         TargetHolders& rTargetHolders,
    1054             :         PropertyHolders& rPropertyHolders)
    1055             :     {
    1056             :         // check if currently active
    1057           9 :         if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1)
    1058             :         {
    1059           0 :             drawinglayer::primitive2d::Primitive2DSequence aSubContent;
    1060             : 
    1061           0 :             if(rTargetHolders.Current().size())
    1062             :             {
    1063           0 :                 aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
    1064             :             }
    1065             : 
    1066           0 :             rTargetHolders.Pop();
    1067             : 
    1068           0 :             if(aSubContent.hasElements())
    1069             :             {
    1070           0 :                 if(rPropertyHolders.Current().isRasterOpForceBlack())
    1071             :                 {
    1072             :                     // force content to black
    1073           0 :                     rTargetHolders.Current().append(
    1074             :                         new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
    1075             :                             aSubContent,
    1076           0 :                             basegfx::BColorModifier(basegfx::BColor(0.0, 0.0, 0.0))));
    1077             :                 }
    1078             :                 else // if(rPropertyHolders.Current().isRasterOpInvert())
    1079             :                 {
    1080             :                     // invert content
    1081           0 :                     rTargetHolders.Current().append(
    1082             :                         new drawinglayer::primitive2d::InvertPrimitive2D(
    1083           0 :                             aSubContent));
    1084             :                 }
    1085           0 :             }
    1086             :         }
    1087             : 
    1088             :         // apply new settings
    1089           9 :         rPropertyHolders.Current().setRasterOp(aRasterOp);
    1090             : 
    1091             :         // check if now active
    1092           9 :         if(rPropertyHolders.Current().isRasterOpActive())
    1093             :         {
    1094             :             // prepare new content holder for new invert
    1095           0 :             rTargetHolders.Push();
    1096             :         }
    1097           9 :     }
    1098             : 
    1099             :     /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
    1100             :         It is a quite mighty action. This helper is for simple color filled background.
    1101             :      */
    1102           0 :     drawinglayer::primitive2d::BasePrimitive2D* CreateColorWallpaper(
    1103             :         const basegfx::B2DRange& rRange,
    1104             :         const basegfx::BColor& rColor,
    1105             :         PropertyHolder& rPropertyHolder)
    1106             :     {
    1107           0 :         basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange));
    1108           0 :         aOutline.transform(rPropertyHolder.getTransformation());
    1109             : 
    1110             :         return new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
    1111             :             basegfx::B2DPolyPolygon(aOutline),
    1112           0 :             rColor);
    1113             :     }
    1114             : 
    1115             :     /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
    1116             :         It is a quite mighty action. This helper is for gradient filled background.
    1117             :      */
    1118           0 :     drawinglayer::primitive2d::BasePrimitive2D* CreateGradientWallpaper(
    1119             :         const basegfx::B2DRange& rRange,
    1120             :         const Gradient& rGradient,
    1121             :         PropertyHolder& rPropertyHolder)
    1122             :     {
    1123           0 :         const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
    1124             : 
    1125           0 :         if(aAttribute.getStartColor() == aAttribute.getEndColor())
    1126             :         {
    1127             :             // not really a gradient. Create filled rectangle
    1128           0 :             return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder);
    1129             :         }
    1130             :         else
    1131             :         {
    1132             :             // really a gradient
    1133             :             drawinglayer::primitive2d::BasePrimitive2D* pRetval =
    1134             :                 new drawinglayer::primitive2d::FillGradientPrimitive2D(
    1135             :                     rRange,
    1136           0 :                     aAttribute);
    1137             : 
    1138           0 :             if(!rPropertyHolder.getTransformation().isIdentity())
    1139             :             {
    1140           0 :                 const drawinglayer::primitive2d::Primitive2DReference xPrim(pRetval);
    1141           0 :                 const drawinglayer::primitive2d::Primitive2DSequence xSeq(&xPrim, 1);
    1142             : 
    1143             :                 pRetval = new drawinglayer::primitive2d::TransformPrimitive2D(
    1144             :                     rPropertyHolder.getTransformation(),
    1145           0 :                     xSeq);
    1146             :             }
    1147             : 
    1148           0 :             return pRetval;
    1149           0 :         }
    1150             :     }
    1151             : 
    1152             :     /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
    1153             :         It is a quite mighty action. This helper decides if color and/or gradient
    1154             :         background is needed for the wnated bitmap fill and then creates the needed
    1155             :         WallpaperBitmapPrimitive2D. This primitive was created for this purpose and
    1156             :         takes over all needed logic of orientations and tiling.
    1157             :      */
    1158           0 :     void CreateAndAppendBitmapWallpaper(
    1159             :         basegfx::B2DRange aWallpaperRange,
    1160             :         const Wallpaper& rWallpaper,
    1161             :         TargetHolder& rTarget,
    1162             :         PropertyHolder& rProperty)
    1163             :     {
    1164           0 :         const BitmapEx aBitmapEx(rWallpaper.GetBitmap());
    1165           0 :         const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
    1166             : 
    1167             :         // if bitmap visualisation is transparent, maybe background
    1168             :         // needs to be filled. Create background
    1169           0 :         if(aBitmapEx.IsTransparent()
    1170             :             || (WALLPAPER_TILE != eWallpaperStyle && WALLPAPER_SCALE != eWallpaperStyle))
    1171             :         {
    1172           0 :             if(rWallpaper.IsGradient())
    1173             :             {
    1174             :                 rTarget.append(
    1175             :                     CreateGradientWallpaper(
    1176             :                         aWallpaperRange,
    1177             :                         rWallpaper.GetGradient(),
    1178           0 :                         rProperty));
    1179             :             }
    1180           0 :             else if(!rWallpaper.GetColor().GetTransparency())
    1181             :             {
    1182             :                 rTarget.append(
    1183             :                     CreateColorWallpaper(
    1184             :                         aWallpaperRange,
    1185           0 :                         rWallpaper.GetColor().getBColor(),
    1186           0 :                         rProperty));
    1187             :             }
    1188             :         }
    1189             : 
    1190             :         // use wallpaper rect if set
    1191           0 :         if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty())
    1192             :         {
    1193             :             aWallpaperRange = basegfx::B2DRange(
    1194           0 :                 rWallpaper.GetRect().Left(), rWallpaper.GetRect().Top(),
    1195           0 :                 rWallpaper.GetRect().Right(), rWallpaper.GetRect().Bottom());
    1196             :         }
    1197             : 
    1198             :         drawinglayer::primitive2d::BasePrimitive2D* pBitmapWallpaperFill =
    1199             :             new drawinglayer::primitive2d::WallpaperBitmapPrimitive2D(
    1200             :                 aWallpaperRange,
    1201             :                 aBitmapEx,
    1202           0 :                 eWallpaperStyle);
    1203             : 
    1204           0 :         if(rProperty.getTransformation().isIdentity())
    1205             :         {
    1206             :             // add directly
    1207           0 :             rTarget.append(pBitmapWallpaperFill);
    1208             :         }
    1209             :         else
    1210             :         {
    1211             :             // when a transformation is set, embed to it
    1212           0 :             const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill);
    1213             : 
    1214             :             rTarget.append(
    1215             :                 new drawinglayer::primitive2d::TransformPrimitive2D(
    1216             :                     rProperty.getTransformation(),
    1217           0 :                     drawinglayer::primitive2d::Primitive2DSequence(&xPrim, 1)));
    1218           0 :         }
    1219           0 :     }
    1220             : 
    1221             :     /** helper to decide UnderlineAbove for text primitives */
    1222           0 :     bool isUnderlineAbove(const Font& rFont)
    1223             :     {
    1224           0 :         if(!rFont.IsVertical())
    1225             :         {
    1226           0 :             return false;
    1227             :         }
    1228             : 
    1229           0 :         if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
    1230             :         {
    1231             :             // the underline is right for Japanese only
    1232           0 :             return true;
    1233             :         }
    1234             : 
    1235           0 :         return false;
    1236             :     }
    1237             : 
    1238           0 :     void createFontAttributeTransformAndAlignment(
    1239             :         drawinglayer::attribute::FontAttribute& rFontAttribute,
    1240             :         basegfx::B2DHomMatrix& rTextTransform,
    1241             :         basegfx::B2DVector& rAlignmentOffset,
    1242             :         PropertyHolder& rProperty)
    1243             :     {
    1244           0 :         const Font& rFont = rProperty.getFont();
    1245           0 :         basegfx::B2DVector aFontScaling;
    1246             : 
    1247             :         rFontAttribute = drawinglayer::attribute::FontAttribute(
    1248             :             drawinglayer::primitive2d::getFontAttributeFromVclFont(
    1249             :                 aFontScaling,
    1250             :                 rFont,
    1251           0 :                 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_RTL),
    1252           0 :                 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_STRONG)));
    1253             : 
    1254             :         // add FontScaling
    1255           0 :         rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY());
    1256             : 
    1257             :         // take text align into account
    1258           0 :         if(ALIGN_BASELINE != rFont.GetAlign())
    1259             :         {
    1260           0 :             drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
    1261           0 :             aTextLayouterDevice.setFont(rFont);
    1262             : 
    1263           0 :             if(ALIGN_TOP == rFont.GetAlign())
    1264             :             {
    1265           0 :                 rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent());
    1266             :             }
    1267             :             else // ALIGN_BOTTOM
    1268             :             {
    1269           0 :                 rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent());
    1270             :             }
    1271             : 
    1272           0 :             rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY());
    1273             :         }
    1274             : 
    1275             :         // add FontRotation (if used)
    1276           0 :         if(rFont.GetOrientation())
    1277             :         {
    1278           0 :             rTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
    1279           0 :         }
    1280           0 :     }
    1281             : 
    1282             :     /** helper which takes complete care for creating the needed text primitives. It
    1283             :         takes care of decorated stuff and all the geometry adaptions needed
    1284             :      */
    1285           0 :     void processMetaTextAction(
    1286             :         const Point& rTextStartPosition,
    1287             :         const OUString& rText,
    1288             :         sal_uInt16 nTextStart,
    1289             :         sal_uInt16 nTextLength,
    1290             :         const ::std::vector< double >& rDXArray,
    1291             :         TargetHolder& rTarget,
    1292             :         PropertyHolder& rProperty)
    1293             :     {
    1294           0 :         drawinglayer::primitive2d::BasePrimitive2D* pResult = 0;
    1295           0 :         const Font& rFont = rProperty.getFont();
    1296           0 :         basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
    1297             : 
    1298           0 :         if(nTextLength)
    1299             :         {
    1300           0 :             drawinglayer::attribute::FontAttribute aFontAttribute;
    1301           0 :             basegfx::B2DHomMatrix aTextTransform;
    1302             : 
    1303             :             // fill parameters derived from current font
    1304             :             createFontAttributeTransformAndAlignment(
    1305             :                 aFontAttribute,
    1306             :                 aTextTransform,
    1307             :                 aAlignmentOffset,
    1308           0 :                 rProperty);
    1309             : 
    1310             :             // add TextStartPosition
    1311           0 :             aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
    1312             : 
    1313             :             // prepare FontColor and Locale
    1314           0 :             const basegfx::BColor aFontColor(rProperty.getTextColor());
    1315           0 :             const com::sun::star::lang::Locale aLocale(LanguageTag(rProperty.getLanguageType()).getLocale());
    1316           0 :             const bool bWordLineMode(rFont.IsWordLineMode());
    1317             : 
    1318             :             const bool bDecoratedIsNeeded(
    1319           0 :                    UNDERLINE_NONE != rFont.GetOverline()
    1320           0 :                 || UNDERLINE_NONE != rFont.GetUnderline()
    1321           0 :                 || STRIKEOUT_NONE != rFont.GetStrikeout()
    1322           0 :                 || EMPHASISMARK_NONE != (rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
    1323           0 :                 || RELIEF_NONE != rFont.GetRelief()
    1324           0 :                 || rFont.IsShadow()
    1325           0 :                 || bWordLineMode);
    1326             : 
    1327           0 :             if(bDecoratedIsNeeded)
    1328             :             {
    1329             :                 // prepare overline, underline and srikeout data
    1330           0 :                 const drawinglayer::primitive2d::TextLine eFontOverline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetOverline()));
    1331           0 :                 const drawinglayer::primitive2d::TextLine eFontUnderline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetUnderline()));
    1332           0 :                 const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rFont.GetStrikeout()));
    1333             : 
    1334             :                 // check UndelineAbove
    1335           0 :                 const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && isUnderlineAbove(rFont));
    1336             : 
    1337             :                 // prepare emphasis mark data
    1338           0 :                 drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
    1339             : 
    1340           0 :                 switch(rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
    1341             :                 {
    1342           0 :                     case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
    1343           0 :                     case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
    1344           0 :                     case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
    1345           0 :                     case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
    1346             :                 }
    1347             : 
    1348           0 :                 const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
    1349           0 :                 const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
    1350             : 
    1351             :                 // prepare font relief data
    1352           0 :                 drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
    1353             : 
    1354           0 :                 switch(rFont.GetRelief())
    1355             :                 {
    1356           0 :                     case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
    1357           0 :                     case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
    1358           0 :                     default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
    1359             :                 }
    1360             : 
    1361             :                 // prepare shadow/outline data
    1362           0 :                 const bool bShadow(rFont.IsShadow());
    1363             : 
    1364             :                 // TextDecoratedPortionPrimitive2D is needed, create one
    1365             :                 pResult = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
    1366             : 
    1367             :                     // attributes for TextSimplePortionPrimitive2D
    1368             :                     aTextTransform,
    1369             :                     rText,
    1370             :                     nTextStart,
    1371             :                     nTextLength,
    1372             :                     rDXArray,
    1373             :                     aFontAttribute,
    1374             :                     aLocale,
    1375             :                     aFontColor,
    1376             : 
    1377             :                     // attributes for TextDecoratedPortionPrimitive2D
    1378           0 :                     rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor,
    1379           0 :                     rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor,
    1380             :                     eFontOverline,
    1381             :                     eFontUnderline,
    1382             :                     bUnderlineAbove,
    1383             :                     eTextStrikeout,
    1384             :                     bWordLineMode,
    1385             :                     eTextEmphasisMark,
    1386             :                     bEmphasisMarkAbove,
    1387             :                     bEmphasisMarkBelow,
    1388             :                     eTextRelief,
    1389           0 :                     bShadow);
    1390             :             }
    1391             :             else
    1392             :             {
    1393             :                 // TextSimplePortionPrimitive2D is enough
    1394             :                 pResult = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
    1395             :                     aTextTransform,
    1396             :                     rText,
    1397             :                     nTextStart,
    1398             :                     nTextLength,
    1399             :                     rDXArray,
    1400             :                     aFontAttribute,
    1401             :                     aLocale,
    1402           0 :                     aFontColor);
    1403           0 :             }
    1404             :         }
    1405             : 
    1406           0 :         if(pResult && rProperty.getTextFillColorActive())
    1407             :         {
    1408             :             // text background is requested, add and encapsulate both to new primitive
    1409           0 :             drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
    1410           0 :             aTextLayouterDevice.setFont(rFont);
    1411             : 
    1412             :             // get text width
    1413           0 :             double fTextWidth(0.0);
    1414             : 
    1415           0 :             if(rDXArray.empty())
    1416             :             {
    1417           0 :                 fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength);
    1418             :             }
    1419             :             else
    1420             :             {
    1421           0 :                 fTextWidth = rDXArray.back();
    1422             :             }
    1423             : 
    1424           0 :             if(basegfx::fTools::more(fTextWidth, 0.0))
    1425             :             {
    1426             :                 // build text range
    1427             :                 const basegfx::B2DRange aTextRange(
    1428           0 :                     0.0, -aTextLayouterDevice.getFontAscent(),
    1429           0 :                     fTextWidth, aTextLayouterDevice.getFontDescent());
    1430             : 
    1431             :                 // create Transform
    1432           0 :                 basegfx::B2DHomMatrix aTextTransform;
    1433             : 
    1434           0 :                 aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY());
    1435             : 
    1436           0 :                 if(rFont.GetOrientation())
    1437             :                 {
    1438           0 :                     aTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
    1439             :                 }
    1440             : 
    1441           0 :                 aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
    1442             : 
    1443             :                 // prepare Primitive2DSequence, put text in foreground
    1444           0 :                 drawinglayer::primitive2d::Primitive2DSequence aSequence(2);
    1445           0 :                 aSequence[1] = drawinglayer::primitive2d::Primitive2DReference(pResult);
    1446             : 
    1447             :                 // prepare filled polygon
    1448           0 :                 basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aTextRange));
    1449           0 :                 aOutline.transform(aTextTransform);
    1450             : 
    1451           0 :                 aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(
    1452             :                     new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
    1453             :                         basegfx::B2DPolyPolygon(aOutline),
    1454           0 :                         rProperty.getTextFillColor()));
    1455             : 
    1456             :                 // set as group at pResult
    1457           0 :                 pResult = new drawinglayer::primitive2d::GroupPrimitive2D(aSequence);
    1458           0 :             }
    1459             :         }
    1460             : 
    1461           0 :         if(pResult)
    1462             :         {
    1463             :             // add created text primitive to target
    1464           0 :             if(rProperty.getTransformation().isIdentity())
    1465             :             {
    1466           0 :                 rTarget.append(pResult);
    1467             :             }
    1468             :             else
    1469             :             {
    1470             :                 // when a transformation is set, embed to it
    1471           0 :                 const drawinglayer::primitive2d::Primitive2DReference aReference(pResult);
    1472             : 
    1473             :                 rTarget.append(
    1474             :                     new drawinglayer::primitive2d::TransformPrimitive2D(
    1475             :                         rProperty.getTransformation(),
    1476           0 :                         drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1)));
    1477             :             }
    1478           0 :         }
    1479           0 :     }
    1480             : 
    1481             :     /** helper which takes complete care for creating the needed textLine primitives */
    1482           0 :     void proccessMetaTextLineAction(
    1483             :         const MetaTextLineAction& rAction,
    1484             :         TargetHolder& rTarget,
    1485             :         PropertyHolder& rProperty)
    1486             :     {
    1487           0 :         const double fLineWidth(fabs((double)rAction.GetWidth()));
    1488             : 
    1489           0 :         if(fLineWidth > 0.0)
    1490             :         {
    1491           0 :             const drawinglayer::primitive2d::TextLine aOverlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetOverline()));
    1492           0 :             const drawinglayer::primitive2d::TextLine aUnderlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetUnderline()));
    1493           0 :             const drawinglayer::primitive2d::TextStrikeout aTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rAction.GetStrikeout()));
    1494             : 
    1495           0 :             const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode);
    1496           0 :             const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode);
    1497           0 :             const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout);
    1498             : 
    1499           0 :             if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
    1500             :             {
    1501           0 :                 std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargetVector;
    1502           0 :                 basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
    1503           0 :                 drawinglayer::attribute::FontAttribute aFontAttribute;
    1504           0 :                 basegfx::B2DHomMatrix aTextTransform;
    1505             : 
    1506             :                 // fill parameters derived from current font
    1507             :                 createFontAttributeTransformAndAlignment(
    1508             :                     aFontAttribute,
    1509             :                     aTextTransform,
    1510             :                     aAlignmentOffset,
    1511           0 :                     rProperty);
    1512             : 
    1513             :                 // add TextStartPosition
    1514           0 :                 aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y());
    1515             : 
    1516             :                 // prepare TextLayouter (used in most cases)
    1517           0 :                 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
    1518           0 :                 aTextLayouter.setFont(rProperty.getFont());
    1519             : 
    1520           0 :                 if(bOverlineUsed)
    1521             :                 {
    1522             :                     // create primitive geometry for overline
    1523             :                     aTargetVector.push_back(
    1524             :                         new drawinglayer::primitive2d::TextLinePrimitive2D(
    1525             :                             aTextTransform,
    1526             :                             fLineWidth,
    1527             :                             aTextLayouter.getOverlineOffset(),
    1528             :                             aTextLayouter.getOverlineHeight(),
    1529             :                             aOverlineMode,
    1530           0 :                             rProperty.getOverlineColor()));
    1531             :                 }
    1532             : 
    1533           0 :                 if(bUnderlineUsed)
    1534             :                 {
    1535             :                     // create primitive geometry for underline
    1536             :                     aTargetVector.push_back(
    1537             :                         new drawinglayer::primitive2d::TextLinePrimitive2D(
    1538             :                             aTextTransform,
    1539             :                             fLineWidth,
    1540             :                             aTextLayouter.getUnderlineOffset(),
    1541             :                             aTextLayouter.getUnderlineHeight(),
    1542             :                             aUnderlineMode,
    1543           0 :                             rProperty.getTextLineColor()));
    1544             :                 }
    1545             : 
    1546           0 :                 if(bStrikeoutUsed)
    1547             :                 {
    1548             :                     // create primitive geometry for strikeout
    1549           0 :                     if(drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout
    1550             :                         || drawinglayer::primitive2d::TEXT_STRIKEOUT_X == aTextStrikeout)
    1551             :                     {
    1552             :                         // strikeout with character
    1553             :                         const sal_Unicode aStrikeoutChar(
    1554           0 :                             drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X');
    1555             :                         const com::sun::star::lang::Locale aLocale(LanguageTag(
    1556           0 :                             rProperty.getLanguageType()).getLocale());
    1557             : 
    1558             :                         aTargetVector.push_back(
    1559             :                             new drawinglayer::primitive2d::TextCharacterStrikeoutPrimitive2D(
    1560             :                                 aTextTransform,
    1561             :                                 fLineWidth,
    1562             :                                 rProperty.getTextColor(),
    1563             :                                 aStrikeoutChar,
    1564             :                                 aFontAttribute,
    1565           0 :                                 aLocale));
    1566             :                     }
    1567             :                     else
    1568             :                     {
    1569             :                         // strikeout with geometry
    1570             :                         aTargetVector.push_back(
    1571             :                             new drawinglayer::primitive2d::TextGeometryStrikeoutPrimitive2D(
    1572             :                                 aTextTransform,
    1573             :                                 fLineWidth,
    1574             :                                 rProperty.getTextColor(),
    1575             :                                 aTextLayouter.getUnderlineHeight(),
    1576             :                                 aTextLayouter.getStrikeoutOffset(),
    1577           0 :                                 aTextStrikeout));
    1578             :                     }
    1579             :                 }
    1580             : 
    1581           0 :                 if(!aTargetVector.empty())
    1582             :                 {
    1583             :                     // add created text primitive to target
    1584           0 :                     if(rProperty.getTransformation().isIdentity())
    1585             :                     {
    1586           0 :                         for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
    1587             :                         {
    1588           0 :                             rTarget.append(aTargetVector[a]);
    1589             :                         }
    1590             :                     }
    1591             :                     else
    1592             :                     {
    1593             :                         // when a transformation is set, embed to it
    1594           0 :                         drawinglayer::primitive2d::Primitive2DSequence xTargets(aTargetVector.size());
    1595             : 
    1596           0 :                         for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
    1597             :                         {
    1598           0 :                             xTargets[a] = drawinglayer::primitive2d::Primitive2DReference(aTargetVector[a]);
    1599             :                         }
    1600             : 
    1601             :                         rTarget.append(
    1602             :                             new drawinglayer::primitive2d::TransformPrimitive2D(
    1603             :                                 rProperty.getTransformation(),
    1604           0 :                                 xTargets));
    1605             :                     }
    1606           0 :                 }
    1607             :             }
    1608             :         }
    1609             : 
    1610           0 :     }
    1611             : 
    1612             :     /** This is the main interpreter method. It is designed to handle the given Metafile
    1613             :         completely inside the given context and target. It may use and modify the context and
    1614             :         target. This design allows to call itself recursively wich adapted contexts and
    1615             :         targets as e.g. needed for the META_FLOATTRANSPARENT_ACTION where the content is expressed
    1616             :         as a metafile as sub-content.
    1617             : 
    1618             :         This interpreter is as free of VCL functionality as possible. It uses VCL data classes
    1619             :         (else reading the data would not be possible), but e.g. does NOT use a local OutputDevice
    1620             :         as most other MetaFile interpreters/exporters do to hold and work with the current context.
    1621             :         This is necessary to be able to get away from the strong internal VCL-binding.
    1622             : 
    1623             :         It tries to combine e.g. pixel and/or point actions and to stitch together single line primitives
    1624             :         where possible (which is not trivial with the possible line geometry definitions).
    1625             : 
    1626             :         It tries to handle clipping no longer as Regions and spans of Rectangles, but as PolyPolygon
    1627             :         ClipRegions with (where possible) high precision by using the best possible data quality
    1628             :         from the Region. The Region is unavoidable as data container, but nowadays allows the transport
    1629             :         of Polygon-based clip regions. Where this is not used, a Polygon is constructed from the
    1630             :         Region ranges. All primitive clipping uses the MaskPrimitive2D with Polygon-based clipping.
    1631             : 
    1632             :         I have marked the single MetaActions with:
    1633             : 
    1634             :         SIMPLE, DONE:
    1635             :         Simple, e.g nothing to do or value setting in the context
    1636             : 
    1637             :         CHECKED, WORKS WELL:
    1638             :         Thoroughly tested with extra written test code which created a replacement
    1639             :         Metafile just to test this action in various combinations
    1640             : 
    1641             :         NEEDS IMPLEMENTATION:
    1642             :         Not implemented and asserted, but also no usage found, neither in own Metafile
    1643             :         creations, nor in EMF/WMF imports (checked with a whole bunch of critical EMF/WMF
    1644             :         bugdocs)
    1645             : 
    1646             :         For more commens, see the single action implementations.
    1647             :     */
    1648           1 :     void interpretMetafile(
    1649             :         const GDIMetaFile& rMetaFile,
    1650             :         TargetHolders& rTargetHolders,
    1651             :         PropertyHolders& rPropertyHolders,
    1652             :         const drawinglayer::geometry::ViewInformation2D& rViewInformation)
    1653             :     {
    1654           1 :         const size_t nCount(rMetaFile.GetActionSize());
    1655             : 
    1656          92 :         for(size_t nAction(0); nAction < nCount; nAction++)
    1657             :         {
    1658          91 :             MetaAction* pAction = rMetaFile.GetAction(nAction);
    1659             : 
    1660          91 :             switch(pAction->GetType())
    1661             :             {
    1662             :                 case META_NULL_ACTION :
    1663             :                 {
    1664             :                     /** SIMPLE, DONE */
    1665           0 :                     break;
    1666             :                 }
    1667             :                 case META_PIXEL_ACTION :
    1668             :                 {
    1669             :                     /** CHECKED, WORKS WELL */
    1670           0 :                     std::vector< basegfx::B2DPoint > aPositions;
    1671           0 :                     Color aLastColor(COL_BLACK);
    1672             : 
    1673           0 :                     while(META_PIXEL_ACTION == pAction->GetType() && nAction < nCount)
    1674             :                     {
    1675           0 :                         const MetaPixelAction* pA = (const MetaPixelAction*)pAction;
    1676             : 
    1677           0 :                         if(pA->GetColor() != aLastColor)
    1678             :                         {
    1679           0 :                             if(!aPositions.empty())
    1680             :                             {
    1681           0 :                                 createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
    1682           0 :                                 aPositions.clear();
    1683             :                             }
    1684             : 
    1685           0 :                             aLastColor = pA->GetColor();
    1686             :                         }
    1687             : 
    1688           0 :                         const Point& rPoint = pA->GetPoint();
    1689           0 :                         aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
    1690           0 :                         nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
    1691             :                     }
    1692             : 
    1693           0 :                     nAction--;
    1694             : 
    1695           0 :                     if(!aPositions.empty())
    1696             :                     {
    1697           0 :                         createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
    1698             :                     }
    1699             : 
    1700           0 :                     break;
    1701             :                 }
    1702             :                 case META_POINT_ACTION :
    1703             :                 {
    1704             :                     /** CHECKED, WORKS WELL */
    1705           0 :                     if(rPropertyHolders.Current().getLineColorActive())
    1706             :                     {
    1707           0 :                         std::vector< basegfx::B2DPoint > aPositions;
    1708             : 
    1709           0 :                         while(META_POINT_ACTION == pAction->GetType() && nAction < nCount)
    1710             :                         {
    1711           0 :                             const MetaPointAction* pA = (const MetaPointAction*)pAction;
    1712           0 :                             const Point& rPoint = pA->GetPoint();
    1713           0 :                             aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
    1714           0 :                             nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
    1715             :                         }
    1716             : 
    1717           0 :                         nAction--;
    1718             : 
    1719           0 :                         if(!aPositions.empty())
    1720             :                         {
    1721           0 :                             createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor());
    1722           0 :                         }
    1723             :                     }
    1724             : 
    1725           0 :                     break;
    1726             :                 }
    1727             :                 case META_LINE_ACTION :
    1728             :                 {
    1729             :                     /** CHECKED, WORKS WELL */
    1730           0 :                     if(rPropertyHolders.Current().getLineColorActive())
    1731             :                     {
    1732           0 :                         basegfx::B2DPolygon aLinePolygon;
    1733           0 :                         LineInfo aLineInfo;
    1734             : 
    1735           0 :                         while(META_LINE_ACTION == pAction->GetType() && nAction < nCount)
    1736             :                         {
    1737           0 :                             const MetaLineAction* pA = (const MetaLineAction*)pAction;
    1738           0 :                             const Point& rStartPoint = pA->GetStartPoint();
    1739           0 :                             const Point& rEndPoint = pA->GetEndPoint();
    1740           0 :                             const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y());
    1741           0 :                             const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y());
    1742             : 
    1743           0 :                             if(aLinePolygon.count())
    1744             :                             {
    1745           0 :                                 if(pA->GetLineInfo() == aLineInfo
    1746           0 :                                     && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1))
    1747             :                                 {
    1748           0 :                                     aLinePolygon.append(aEnd);
    1749             :                                 }
    1750             :                                 else
    1751             :                                 {
    1752           0 :                                     aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
    1753           0 :                                     createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
    1754           0 :                                     aLinePolygon.clear();
    1755           0 :                                     aLineInfo = pA->GetLineInfo();
    1756           0 :                                     aLinePolygon.append(aStart);
    1757           0 :                                     aLinePolygon.append(aEnd);
    1758             :                                 }
    1759             :                             }
    1760             :                             else
    1761             :                             {
    1762           0 :                                 aLineInfo = pA->GetLineInfo();
    1763           0 :                                 aLinePolygon.append(aStart);
    1764           0 :                                 aLinePolygon.append(aEnd);
    1765             :                             }
    1766             : 
    1767           0 :                             nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
    1768           0 :                         }
    1769             : 
    1770           0 :                         nAction--;
    1771             : 
    1772           0 :                         if(aLinePolygon.count())
    1773             :                         {
    1774           0 :                             aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
    1775           0 :                             createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
    1776           0 :                         }
    1777             :                     }
    1778             : 
    1779           0 :                     break;
    1780             :                 }
    1781             :                 case META_RECT_ACTION :
    1782             :                 {
    1783             :                     /** CHECKED, WORKS WELL */
    1784           0 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1785             :                     {
    1786           0 :                         const MetaRectAction* pA = (const MetaRectAction*)pAction;
    1787           0 :                         const Rectangle& rRectangle = pA->GetRect();
    1788             : 
    1789           0 :                         if(!rRectangle.IsEmpty())
    1790             :                         {
    1791           0 :                             const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
    1792             : 
    1793           0 :                             if(!aRange.isEmpty())
    1794             :                             {
    1795           0 :                                 const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
    1796           0 :                                 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1797             :                             }
    1798             :                         }
    1799             :                     }
    1800             : 
    1801           0 :                     break;
    1802             :                 }
    1803             :                 case META_ROUNDRECT_ACTION :
    1804             :                 {
    1805             :                     /** CHECKED, WORKS WELL */
    1806             :                     /** The original OutputDevice::DrawRect paints nothing when nHor or nVer is zero; but just
    1807             :                         because the tools::Polygon operator creating the rounding does produce nonsense. I assume
    1808             :                         this an error and create an unrounded rectangle in that case (implicit in
    1809             :                         createPolygonFromRect)
    1810             :                      */
    1811           0 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1812             :                     {
    1813           0 :                         const MetaRoundRectAction* pA = (const MetaRoundRectAction*)pAction;
    1814           0 :                         const Rectangle& rRectangle = pA->GetRect();
    1815             : 
    1816           0 :                         if(!rRectangle.IsEmpty())
    1817             :                         {
    1818           0 :                             const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
    1819             : 
    1820           0 :                             if(!aRange.isEmpty())
    1821             :                             {
    1822           0 :                                 const sal_uInt32 nHor(pA->GetHorzRound());
    1823           0 :                                 const sal_uInt32 nVer(pA->GetVertRound());
    1824           0 :                                 basegfx::B2DPolygon aOutline;
    1825             : 
    1826           0 :                                 if(nHor || nVer)
    1827             :                                 {
    1828           0 :                                     double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
    1829           0 :                                     double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
    1830           0 :                                     fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
    1831           0 :                                     fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
    1832             : 
    1833           0 :                                     aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
    1834             :                                 }
    1835             :                                 else
    1836             :                                 {
    1837           0 :                                     aOutline = basegfx::tools::createPolygonFromRect(aRange);
    1838             :                                 }
    1839             : 
    1840           0 :                                 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1841             :                             }
    1842             :                         }
    1843             :                     }
    1844             : 
    1845           0 :                     break;
    1846             :                 }
    1847             :                 case META_ELLIPSE_ACTION :
    1848             :                 {
    1849             :                     /** CHECKED, WORKS WELL */
    1850           0 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1851             :                     {
    1852           0 :                         const MetaEllipseAction* pA = (const MetaEllipseAction*)pAction;
    1853           0 :                         const Rectangle& rRectangle = pA->GetRect();
    1854             : 
    1855           0 :                         if(!rRectangle.IsEmpty())
    1856             :                         {
    1857           0 :                             const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
    1858             : 
    1859           0 :                             if(!aRange.isEmpty())
    1860             :                             {
    1861             :                                 const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromEllipse(
    1862           0 :                                     aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5));
    1863             : 
    1864           0 :                                 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1865             :                             }
    1866             :                         }
    1867             :                     }
    1868             : 
    1869           0 :                     break;
    1870             :                 }
    1871             :                 case META_ARC_ACTION :
    1872             :                 {
    1873             :                     /** CHECKED, WORKS WELL */
    1874           0 :                     if(rPropertyHolders.Current().getLineColorActive())
    1875             :                     {
    1876           0 :                         const MetaArcAction* pA = (const MetaArcAction*)pAction;
    1877           0 :                         const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC);
    1878           0 :                         const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
    1879             : 
    1880           0 :                         createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1881             :                     }
    1882             : 
    1883           0 :                     break;
    1884             :                 }
    1885             :                 case META_PIE_ACTION :
    1886             :                 {
    1887             :                     /** CHECKED, WORKS WELL */
    1888           0 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1889             :                     {
    1890           0 :                         const MetaPieAction* pA = (const MetaPieAction*)pAction;
    1891           0 :                         const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE);
    1892           0 :                         const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
    1893             : 
    1894           0 :                         createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1895             :                     }
    1896             : 
    1897           0 :                     break;
    1898             :                 }
    1899             :                 case META_CHORD_ACTION :
    1900             :                 {
    1901             :                     /** CHECKED, WORKS WELL */
    1902           0 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1903             :                     {
    1904           0 :                         const MetaChordAction* pA = (const MetaChordAction*)pAction;
    1905           0 :                         const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD);
    1906           0 :                         const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
    1907             : 
    1908           0 :                         createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1909             :                     }
    1910             : 
    1911           0 :                     break;
    1912             :                 }
    1913             :                 case META_POLYLINE_ACTION :
    1914             :                 {
    1915             :                     /** CHECKED, WORKS WELL */
    1916           0 :                     if(rPropertyHolders.Current().getLineColorActive())
    1917             :                     {
    1918           0 :                         const MetaPolyLineAction* pA = (const MetaPolyLineAction*)pAction;
    1919           0 :                         createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current());
    1920             :                     }
    1921             : 
    1922           0 :                     break;
    1923             :                 }
    1924             :                 case META_POLYGON_ACTION :
    1925             :                 {
    1926             :                     /** CHECKED, WORKS WELL */
    1927           6 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1928             :                     {
    1929           6 :                         const MetaPolygonAction* pA = (const MetaPolygonAction*)pAction;
    1930           6 :                         basegfx::B2DPolygon aOutline(pA->GetPolygon().getB2DPolygon());
    1931             : 
    1932             :                         // the metafile play interprets the polygons from MetaPolygonAction
    1933             :                         // always as closed and always paints an edge from last to first point,
    1934             :                         // so force to closed here to emulate that
    1935           6 :                         if(aOutline.count() > 1 && !aOutline.isClosed())
    1936             :                         {
    1937           0 :                             aOutline.setClosed(true);
    1938             :                         }
    1939             : 
    1940           6 :                         createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1941             :                     }
    1942             : 
    1943           6 :                     break;
    1944             :                 }
    1945             :                 case META_POLYPOLYGON_ACTION :
    1946             :                 {
    1947             :                     /** CHECKED, WORKS WELL */
    1948          11 :                     if(rPropertyHolders.Current().getLineOrFillActive())
    1949             :                     {
    1950          11 :                         const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*)pAction;
    1951          11 :                         basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
    1952             : 
    1953             :                         // the metafile play interprets the single polygons from MetaPolyPolygonAction
    1954             :                         // always as closed and always paints an edge from last to first point,
    1955             :                         // so force to closed here to emulate that
    1956          30 :                         for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++)
    1957             :                         {
    1958          19 :                             basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b));
    1959             : 
    1960          19 :                             if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed())
    1961             :                             {
    1962           0 :                                 aPolygonOutline.setClosed(true);
    1963           0 :                                 aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline);
    1964             :                             }
    1965          19 :                         }
    1966             : 
    1967          11 :                         createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    1968             :                     }
    1969             : 
    1970          11 :                     break;
    1971             :                 }
    1972             :                 case META_TEXT_ACTION :
    1973             :                 {
    1974             :                     /** CHECKED, WORKS WELL */
    1975           0 :                     const MetaTextAction* pA = (const MetaTextAction*)pAction;
    1976           0 :                     sal_uInt32 nTextLength(pA->GetLen());
    1977           0 :                     const sal_uInt32 nTextIndex(pA->GetIndex());
    1978           0 :                     const sal_uInt32 nStringLength(pA->GetText().getLength());
    1979             : 
    1980           0 :                     if(nTextLength + nTextIndex > nStringLength)
    1981             :                     {
    1982           0 :                         nTextLength = nStringLength - nTextIndex;
    1983             :                     }
    1984             : 
    1985           0 :                     if(nTextLength && rPropertyHolders.Current().getTextColorActive())
    1986             :                     {
    1987           0 :                         const std::vector< double > aDXArray;
    1988             :                         processMetaTextAction(
    1989           0 :                             pA->GetPoint(),
    1990           0 :                             pA->GetText(),
    1991             :                             nTextIndex,
    1992             :                             nTextLength,
    1993             :                             aDXArray,
    1994           0 :                             rTargetHolders.Current(),
    1995           0 :                             rPropertyHolders.Current());
    1996             :                     }
    1997             : 
    1998           0 :                     break;
    1999             :                 }
    2000             :                 case META_TEXTARRAY_ACTION :
    2001             :                 {
    2002             :                     /** CHECKED, WORKS WELL */
    2003           0 :                     const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pAction;
    2004           0 :                     sal_uInt32 nTextLength(pA->GetLen());
    2005           0 :                     const sal_uInt32 nTextIndex(pA->GetIndex());
    2006           0 :                     const sal_uInt32 nStringLength(pA->GetText().getLength());
    2007             : 
    2008           0 :                     if(nTextLength + nTextIndex > nStringLength)
    2009             :                     {
    2010           0 :                         nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex;
    2011             :                     }
    2012             : 
    2013           0 :                     if(nTextLength && rPropertyHolders.Current().getTextColorActive())
    2014             :                     {
    2015             :                         // preapare DXArray (if used)
    2016           0 :                         std::vector< double > aDXArray;
    2017           0 :                         sal_Int32* pDXArray = pA->GetDXArray();
    2018             : 
    2019           0 :                         if(pDXArray)
    2020             :                         {
    2021           0 :                             aDXArray.reserve(nTextLength);
    2022             : 
    2023           0 :                             for(sal_uInt32 a(0); a < nTextLength; a++)
    2024             :                             {
    2025           0 :                                 aDXArray.push_back((double)(*(pDXArray + a)));
    2026             :                             }
    2027             :                         }
    2028             : 
    2029             :                         processMetaTextAction(
    2030           0 :                             pA->GetPoint(),
    2031           0 :                             pA->GetText(),
    2032             :                             nTextIndex,
    2033             :                             nTextLength,
    2034             :                             aDXArray,
    2035           0 :                             rTargetHolders.Current(),
    2036           0 :                             rPropertyHolders.Current());
    2037             :                     }
    2038             : 
    2039           0 :                     break;
    2040             :                 }
    2041             :                 case META_STRETCHTEXT_ACTION :
    2042             :                 {
    2043             :                     // #i108440# StarMath uses MetaStretchTextAction, thus support is needed.
    2044             :                     // It looks as if it pretty never really uses a width different from
    2045             :                     // the default text-layout width, but it's not possible to be sure.
    2046             :                     // Implemented getting the DXArray and checking for scale at all. If
    2047             :                     // scale is more than 3.5% different, scale the DXArray before usage.
    2048             :                     // New status:
    2049             : 
    2050             :                     /** CHECKED, WORKS WELL */
    2051           0 :                     const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pAction;
    2052           0 :                     sal_uInt32 nTextLength(pA->GetLen());
    2053           0 :                     const sal_uInt32 nTextIndex(pA->GetIndex());
    2054           0 :                     const sal_uInt32 nStringLength(pA->GetText().getLength());
    2055             : 
    2056           0 :                     if(nTextLength + nTextIndex > nStringLength)
    2057             :                     {
    2058           0 :                         nTextLength = nStringLength - nTextIndex;
    2059             :                     }
    2060             : 
    2061           0 :                     if(nTextLength && rPropertyHolders.Current().getTextColorActive())
    2062             :                     {
    2063           0 :                         drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
    2064           0 :                         aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
    2065             : 
    2066             :                         ::std::vector< double > aTextArray(
    2067             :                             aTextLayouterDevice.getTextArray(
    2068           0 :                                 pA->GetText(),
    2069             :                                 nTextIndex,
    2070           0 :                                 nTextLength));
    2071             : 
    2072           0 :                         if(!aTextArray.empty())
    2073             :                         {
    2074           0 :                             const double fTextLength(aTextArray.back());
    2075             : 
    2076           0 :                             if(0.0 != fTextLength && pA->GetWidth())
    2077             :                             {
    2078           0 :                                 const double fRelative(pA->GetWidth() / fTextLength);
    2079             : 
    2080           0 :                                 if(fabs(fRelative - 1.0) >= 0.035)
    2081             :                                 {
    2082             :                                     // when derivation is more than 3,5% from default text size,
    2083             :                                     // scale the DXArray
    2084           0 :                                     for(sal_uInt32 a(0); a < aTextArray.size(); a++)
    2085             :                                     {
    2086           0 :                                         aTextArray[a] *= fRelative;
    2087             :                                     }
    2088             :                                 }
    2089             :                             }
    2090             :                         }
    2091             : 
    2092             :                         processMetaTextAction(
    2093           0 :                             pA->GetPoint(),
    2094           0 :                             pA->GetText(),
    2095             :                             nTextIndex,
    2096             :                             nTextLength,
    2097             :                             aTextArray,
    2098           0 :                             rTargetHolders.Current(),
    2099           0 :                             rPropertyHolders.Current());
    2100             :                     }
    2101             : 
    2102           0 :                     break;
    2103             :                 }
    2104             :                 case META_TEXTRECT_ACTION :
    2105             :                 {
    2106             :                     /** CHECKED, WORKS WELL */
    2107             :                     // OSL_FAIL("META_TEXTRECT_ACTION requested (!)");
    2108           0 :                     const MetaTextRectAction* pA = (const MetaTextRectAction*)pAction;
    2109           0 :                     const Rectangle& rRectangle = pA->GetRect();
    2110           0 :                     const sal_uInt32 nStringLength(pA->GetText().getLength());
    2111             : 
    2112           0 :                     if(!rRectangle.IsEmpty() && 0 != nStringLength)
    2113             :                     {
    2114             :                         // The problem with this action is that it describes unlayouted text
    2115             :                         // and the layout capabilities are in EditEngine/Outliner in SVX. The
    2116             :                         // same problem is true for VCL which internally has implementations
    2117             :                         // to layout text in this case. There exists even a call
    2118             :                         // OutputDevice::AddTextRectActions(...) to create the needed actions
    2119             :                         // as 'sub-content' of a Metafile. Unfortunately i do not have an
    2120             :                         // OutputDevice here since this interpreter tries to work without
    2121             :                         // VCL AFAP.
    2122             :                         // Since AddTextRectActions is the only way as long as we do not have
    2123             :                         // a simple text layouter available, i will try to add it to the
    2124             :                         // TextLayouterDevice isloation.
    2125           0 :                         drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
    2126           0 :                         aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
    2127           0 :                         GDIMetaFile aGDIMetaFile;
    2128             : 
    2129             :                         aTextLayouterDevice.addTextRectActions(
    2130           0 :                             rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile);
    2131             : 
    2132           0 :                         if(aGDIMetaFile.GetActionSize())
    2133             :                         {
    2134             :                             // cerate sub-content
    2135           0 :                             drawinglayer::primitive2d::Primitive2DSequence xSubContent;
    2136             :                             {
    2137           0 :                                 rTargetHolders.Push();
    2138             :                                 // #i# for sub-Mteafile contents, do start with new, default render state
    2139           0 :                                 rPropertyHolders.PushDefault();
    2140           0 :                                 interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation);
    2141           0 :                                 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
    2142           0 :                                 rPropertyHolders.Pop();
    2143           0 :                                 rTargetHolders.Pop();
    2144             :                             }
    2145             : 
    2146           0 :                             if(xSubContent.hasElements())
    2147             :                             {
    2148             :                                 // add with transformation
    2149           0 :                                 rTargetHolders.Current().append(
    2150             :                                     new drawinglayer::primitive2d::TransformPrimitive2D(
    2151           0 :                                         rPropertyHolders.Current().getTransformation(),
    2152           0 :                                         xSubContent));
    2153           0 :                             }
    2154           0 :                         }
    2155             :                     }
    2156             : 
    2157           0 :                     break;
    2158             :                 }
    2159             :                 case META_BMP_ACTION :
    2160             :                 {
    2161             :                     /** CHECKED, WORKS WELL */
    2162           0 :                     const MetaBmpAction* pA = (const MetaBmpAction*)pAction;
    2163           0 :                     const BitmapEx aBitmapEx(pA->GetBitmap());
    2164             : 
    2165           0 :                     createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
    2166             : 
    2167           0 :                     break;
    2168             :                 }
    2169             :                 case META_BMPSCALE_ACTION :
    2170             :                 {
    2171             :                     /** CHECKED, WORKS WELL */
    2172           1 :                     const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*)pAction;
    2173           1 :                     const Bitmap aBitmapEx(pA->GetBitmap());
    2174             : 
    2175           1 :                     createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2176             : 
    2177           1 :                     break;
    2178             :                 }
    2179             :                 case META_BMPSCALEPART_ACTION :
    2180             :                 {
    2181             :                     /** CHECKED, WORKS WELL */
    2182           0 :                     const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*)pAction;
    2183           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
    2184             : 
    2185           0 :                     if(!rBitmap.IsEmpty())
    2186             :                     {
    2187           0 :                         Bitmap aCroppedBitmap(rBitmap);
    2188           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
    2189             : 
    2190           0 :                         if(!aCropRectangle.IsEmpty())
    2191             :                         {
    2192           0 :                             aCroppedBitmap.Crop(aCropRectangle);
    2193             :                         }
    2194             : 
    2195           0 :                         const BitmapEx aCroppedBitmapEx(aCroppedBitmap);
    2196           0 :                         createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2197             :                     }
    2198             : 
    2199           0 :                     break;
    2200             :                 }
    2201             :                 case META_BMPEX_ACTION :
    2202             :                 {
    2203             :                     /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
    2204           0 :                     const MetaBmpExAction* pA = (const MetaBmpExAction*)pAction;
    2205           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
    2206             : 
    2207           0 :                     createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
    2208             : 
    2209           0 :                     break;
    2210             :                 }
    2211             :                 case META_BMPEXSCALE_ACTION :
    2212             :                 {
    2213             :                     /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
    2214           0 :                     const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*)pAction;
    2215           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
    2216             : 
    2217           0 :                     createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2218             : 
    2219           0 :                     break;
    2220             :                 }
    2221             :                 case META_BMPEXSCALEPART_ACTION :
    2222             :                 {
    2223             :                     /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
    2224           0 :                     const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*)pAction;
    2225           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
    2226             : 
    2227           0 :                     if(!rBitmapEx.IsEmpty())
    2228             :                     {
    2229           0 :                         BitmapEx aCroppedBitmapEx(rBitmapEx);
    2230           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
    2231             : 
    2232           0 :                         if(!aCropRectangle.IsEmpty())
    2233             :                         {
    2234           0 :                             aCroppedBitmapEx.Crop(aCropRectangle);
    2235             :                         }
    2236             : 
    2237           0 :                         createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2238             :                     }
    2239             : 
    2240           0 :                     break;
    2241             :                 }
    2242             :                 case META_MASK_ACTION :
    2243             :                 {
    2244             :                     /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
    2245           0 :                     const MetaMaskAction* pA = (const MetaMaskAction*)pAction;
    2246           0 :                     const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
    2247             : 
    2248           0 :                     createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
    2249             : 
    2250           0 :                     break;
    2251             :                 }
    2252             :                 case META_MASKSCALE_ACTION :
    2253             :                 {
    2254             :                     /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
    2255           0 :                     const MetaMaskScaleAction* pA = (const MetaMaskScaleAction*)pAction;
    2256           0 :                     const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
    2257             : 
    2258           0 :                     createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2259             : 
    2260           0 :                     break;
    2261             :                 }
    2262             :                 case META_MASKSCALEPART_ACTION :
    2263             :                 {
    2264             :                     /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
    2265           0 :                     const MetaMaskScalePartAction* pA = (const MetaMaskScalePartAction*)pAction;
    2266           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
    2267             : 
    2268           0 :                     if(!rBitmap.IsEmpty())
    2269             :                     {
    2270           0 :                         Bitmap aCroppedBitmap(rBitmap);
    2271           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
    2272             : 
    2273           0 :                         if(!aCropRectangle.IsEmpty())
    2274             :                         {
    2275           0 :                             aCroppedBitmap.Crop(aCropRectangle);
    2276             :                         }
    2277             : 
    2278           0 :                         const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor()));
    2279           0 :                         createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
    2280             :                     }
    2281             : 
    2282           0 :                     break;
    2283             :                 }
    2284             :                 case META_GRADIENT_ACTION :
    2285             :                 {
    2286             :                     /** CHECKED, WORKS WELL */
    2287           0 :                     const MetaGradientAction* pA = (const MetaGradientAction*)pAction;
    2288           0 :                     const Rectangle& rRectangle = pA->GetRect();
    2289             : 
    2290           0 :                     if(!rRectangle.IsEmpty())
    2291             :                     {
    2292           0 :                         basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
    2293             : 
    2294           0 :                         if(!aRange.isEmpty())
    2295             :                         {
    2296           0 :                             const Gradient& rGradient = pA->GetGradient();
    2297           0 :                             const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
    2298           0 :                             basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
    2299             : 
    2300           0 :                             if(aAttribute.getStartColor() == aAttribute.getEndColor())
    2301             :                             {
    2302             :                                 // not really a gradient. Create filled rectangle
    2303             :                                 createFillPrimitive(
    2304             :                                     aOutline,
    2305           0 :                                     rTargetHolders.Current(),
    2306           0 :                                     rPropertyHolders.Current());
    2307             :                             }
    2308             :                             else
    2309             :                             {
    2310             :                                 // really a gradient
    2311           0 :                                 aRange.transform(rPropertyHolders.Current().getTransformation());
    2312           0 :                                 drawinglayer::primitive2d::Primitive2DSequence xGradient(1);
    2313             : 
    2314           0 :                                 if(rPropertyHolders.Current().isRasterOpInvert())
    2315             :                                 {
    2316             :                                     // use a special version of FillGradientPrimitive2D which creates
    2317             :                                     // non-overlapping geometry on decomposition to makethe old XOR
    2318             :                                     // paint 'trick' work.
    2319           0 :                                     xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
    2320             :                                         new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D(
    2321             :                                             aRange,
    2322           0 :                                             aAttribute));
    2323             :                                 }
    2324             :                                 else
    2325             :                                 {
    2326           0 :                                     xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
    2327             :                                         new drawinglayer::primitive2d::FillGradientPrimitive2D(
    2328             :                                             aRange,
    2329           0 :                                             aAttribute));
    2330             :                                 }
    2331             : 
    2332             :                                 // #i112300# clip against polygon representing the rectangle from
    2333             :                                 // the action. This is implicitely done using a temp Clipping in VCL
    2334             :                                 // when a MetaGradientAction is executed
    2335           0 :                                 aOutline.transform(rPropertyHolders.Current().getTransformation());
    2336           0 :                                 rTargetHolders.Current().append(
    2337             :                                     new drawinglayer::primitive2d::MaskPrimitive2D(
    2338             :                                         aOutline,
    2339           0 :                                         xGradient));
    2340           0 :                             }
    2341             :                         }
    2342             :                     }
    2343             : 
    2344           0 :                     break;
    2345             :                 }
    2346             :                 case META_HATCH_ACTION :
    2347             :                 {
    2348             :                     /** CHECKED, WORKS WELL */
    2349           0 :                     const MetaHatchAction* pA = (const MetaHatchAction*)pAction;
    2350           0 :                     basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
    2351             : 
    2352           0 :                     if(aOutline.count())
    2353             :                     {
    2354           0 :                         const Hatch& rHatch = pA->GetHatch();
    2355           0 :                         const drawinglayer::attribute::FillHatchAttribute aAttribute(createFillHatchAttribute(rHatch));
    2356             : 
    2357           0 :                         aOutline.transform(rPropertyHolders.Current().getTransformation());
    2358             : 
    2359           0 :                         const basegfx::B2DRange aObjectRange(aOutline.getB2DRange());
    2360             :                         const drawinglayer::primitive2d::Primitive2DReference aFillHatch(
    2361             :                             new drawinglayer::primitive2d::FillHatchPrimitive2D(
    2362             :                                 aObjectRange,
    2363             :                                 basegfx::BColor(),
    2364           0 :                                 aAttribute));
    2365             : 
    2366           0 :                         rTargetHolders.Current().append(
    2367             :                             new drawinglayer::primitive2d::MaskPrimitive2D(
    2368             :                                 aOutline,
    2369           0 :                                 drawinglayer::primitive2d::Primitive2DSequence(&aFillHatch, 1)));
    2370             :                     }
    2371             : 
    2372           0 :                     break;
    2373             :                 }
    2374             :                 case META_WALLPAPER_ACTION :
    2375             :                 {
    2376             :                     /** CHECKED, WORKS WELL */
    2377           0 :                     const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pAction;
    2378           0 :                     Rectangle aWallpaperRectangle(pA->GetRect());
    2379             : 
    2380           0 :                     if(!aWallpaperRectangle.IsEmpty())
    2381             :                     {
    2382           0 :                         const Wallpaper& rWallpaper = pA->GetWallpaper();
    2383           0 :                            const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
    2384             :                         basegfx::B2DRange aWallpaperRange(
    2385           0 :                             aWallpaperRectangle.Left(), aWallpaperRectangle.Top(),
    2386           0 :                             aWallpaperRectangle.Right(), aWallpaperRectangle.Bottom());
    2387             : 
    2388           0 :                         if(WALLPAPER_NULL != eWallpaperStyle)
    2389             :                         {
    2390           0 :                             if(rWallpaper.IsBitmap())
    2391             :                             {
    2392             :                                 // create bitmap background. Caution: This
    2393             :                                 // also will create gradient/color background(s)
    2394             :                                 // when the bitmap is transparent or not tiled
    2395             :                                 CreateAndAppendBitmapWallpaper(
    2396             :                                     aWallpaperRange,
    2397             :                                     rWallpaper,
    2398           0 :                                     rTargetHolders.Current(),
    2399           0 :                                     rPropertyHolders.Current());
    2400             :                             }
    2401           0 :                             else if(rWallpaper.IsGradient())
    2402             :                             {
    2403             :                                 // create gradient background
    2404           0 :                                 rTargetHolders.Current().append(
    2405             :                                     CreateGradientWallpaper(
    2406             :                                         aWallpaperRange,
    2407             :                                         rWallpaper.GetGradient(),
    2408           0 :                                         rPropertyHolders.Current()));
    2409             :                             }
    2410           0 :                             else if(!rWallpaper.GetColor().GetTransparency())
    2411             :                             {
    2412             :                                 // create color background
    2413           0 :                                 rTargetHolders.Current().append(
    2414             :                                     CreateColorWallpaper(
    2415             :                                         aWallpaperRange,
    2416           0 :                                         rWallpaper.GetColor().getBColor(),
    2417           0 :                                         rPropertyHolders.Current()));
    2418             :                             }
    2419             :                         }
    2420             :                     }
    2421             : 
    2422             :                     break;
    2423             :                 }
    2424             :                 case META_CLIPREGION_ACTION :
    2425             :                 {
    2426             :                     /** CHECKED, WORKS WELL */
    2427           0 :                     const MetaClipRegionAction* pA = (const MetaClipRegionAction*)pAction;
    2428             : 
    2429           0 :                     if(pA->IsClipping())
    2430             :                     {
    2431             :                         // new clipping. Get PolyPolygon and transform with current transformation
    2432           0 :                         basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion()));
    2433             : 
    2434           0 :                         aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
    2435           0 :                         HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
    2436             :                     }
    2437             :                     else
    2438             :                     {
    2439             :                         // end clipping
    2440           0 :                         const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
    2441             : 
    2442           0 :                         HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
    2443             :                     }
    2444             : 
    2445           0 :                     break;
    2446             :                 }
    2447             :                 case META_ISECTRECTCLIPREGION_ACTION :
    2448             :                 {
    2449             :                     /** CHECKED, WORKS WELL */
    2450           5 :                     const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*)pAction;
    2451           5 :                     const Rectangle& rRectangle = pA->GetRect();
    2452             : 
    2453           5 :                     if(rRectangle.IsEmpty())
    2454             :                     {
    2455             :                         // intersect with empty rectangle will always give empty
    2456             :                         // ClipPolyPolygon; start new clipping with empty PolyPolygon
    2457           0 :                         const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
    2458             : 
    2459           0 :                         HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
    2460             :                     }
    2461             :                     else
    2462             :                     {
    2463             :                         // create transformed ClipRange
    2464             :                         basegfx::B2DRange aClipRange(
    2465          10 :                             rRectangle.Left(), rRectangle.Top(),
    2466          15 :                             rRectangle.Right(), rRectangle.Bottom());
    2467             : 
    2468           5 :                         aClipRange.transform(rPropertyHolders.Current().getTransformation());
    2469             : 
    2470           5 :                         if(rPropertyHolders.Current().getClipPolyPolygonActive())
    2471             :                         {
    2472           0 :                             if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
    2473             :                             {
    2474             :                                 // nothing to do, empty active clipPolyPolygon will stay
    2475             :                                 // empty when intersecting
    2476             :                             }
    2477             :                             else
    2478             :                             {
    2479             :                                 // AND existing region and new ClipRange
    2480             :                                 const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
    2481           0 :                                     rPropertyHolders.Current().getClipPolyPolygon());
    2482           0 :                                 basegfx::B2DPolyPolygon aClippedPolyPolygon;
    2483             : 
    2484           0 :                                 if(aOriginalPolyPolygon.count())
    2485             :                                 {
    2486             :                                     aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
    2487             :                                         aOriginalPolyPolygon,
    2488             :                                         aClipRange,
    2489             :                                         true,
    2490           0 :                                         false);
    2491             :                                 }
    2492             : 
    2493           0 :                                 if(aClippedPolyPolygon != aOriginalPolyPolygon)
    2494             :                                 {
    2495             :                                     // start new clipping with intersected region
    2496             :                                     HandleNewClipRegion(
    2497             :                                         aClippedPolyPolygon,
    2498             :                                         rTargetHolders,
    2499           0 :                                         rPropertyHolders);
    2500           0 :                                 }
    2501             :                             }
    2502             :                         }
    2503             :                         else
    2504             :                         {
    2505             :                             // start new clipping with ClipRange
    2506             :                             const basegfx::B2DPolyPolygon aNewClipPolyPolygon(
    2507           5 :                                 basegfx::tools::createPolygonFromRect(aClipRange));
    2508             : 
    2509           5 :                             HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
    2510             :                         }
    2511             :                     }
    2512             : 
    2513           5 :                     break;
    2514             :                 }
    2515             :                 case META_ISECTREGIONCLIPREGION_ACTION :
    2516             :                 {
    2517             :                     /** CHECKED, WORKS WELL */
    2518           0 :                     const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*)pAction;
    2519           0 :                     const Region& rNewRegion = pA->GetRegion();
    2520             : 
    2521           0 :                     if(rNewRegion.IsEmpty())
    2522             :                     {
    2523             :                         // intersect with empty region will always give empty
    2524             :                         // region; start new clipping with empty PolyPolygon
    2525           0 :                         const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
    2526             : 
    2527           0 :                         HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
    2528             :                     }
    2529             :                     else
    2530             :                     {
    2531             :                         // get new ClipPolyPolygon, transform it with current transformation
    2532           0 :                         basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion));
    2533           0 :                         aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
    2534             : 
    2535           0 :                         if(rPropertyHolders.Current().getClipPolyPolygonActive())
    2536             :                         {
    2537           0 :                             if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
    2538             :                             {
    2539             :                                 // nothing to do, empty active clipPolyPolygon will stay empty
    2540             :                                 // when intersecting with any region
    2541             :                             }
    2542             :                             else
    2543             :                             {
    2544             :                                 // AND existing and new region
    2545             :                                 const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
    2546           0 :                                     rPropertyHolders.Current().getClipPolyPolygon());
    2547           0 :                                 basegfx::B2DPolyPolygon aClippedPolyPolygon;
    2548             : 
    2549           0 :                                 if(aOriginalPolyPolygon.count())
    2550             :                                 {
    2551             :                                     aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
    2552           0 :                                         aOriginalPolyPolygon, aNewClipPolyPolygon, true, false);
    2553             :                                 }
    2554             : 
    2555           0 :                                 if(aClippedPolyPolygon != aOriginalPolyPolygon)
    2556             :                                 {
    2557             :                                     // start new clipping with intersected ClipPolyPolygon
    2558           0 :                                     HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders);
    2559           0 :                                 }
    2560             :                             }
    2561             :                         }
    2562             :                         else
    2563             :                         {
    2564             :                             // start new clipping with new ClipPolyPolygon
    2565           0 :                             HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
    2566           0 :                         }
    2567             :                     }
    2568             : 
    2569           0 :                     break;
    2570             :                 }
    2571             :                 case META_MOVECLIPREGION_ACTION :
    2572             :                 {
    2573             :                     /** CHECKED, WORKS WELL */
    2574           0 :                     const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction;
    2575             : 
    2576           0 :                     if(rPropertyHolders.Current().getClipPolyPolygonActive())
    2577             :                     {
    2578           0 :                         if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
    2579             :                         {
    2580             :                             // nothing to do
    2581             :                         }
    2582             :                         else
    2583             :                         {
    2584           0 :                             const sal_Int32 nHor(pA->GetHorzMove());
    2585           0 :                             const sal_Int32 nVer(pA->GetVertMove());
    2586             : 
    2587           0 :                             if(0 != nHor || 0 != nVer)
    2588             :                             {
    2589             :                                 // prepare translation, add current transformation
    2590           0 :                                 basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove());
    2591           0 :                                 aVector *= rPropertyHolders.Current().getTransformation();
    2592             :                                 basegfx::B2DHomMatrix aTransform(
    2593           0 :                                     basegfx::tools::createTranslateB2DHomMatrix(aVector));
    2594             : 
    2595             :                                 // transform existing region
    2596             :                                 basegfx::B2DPolyPolygon aClipPolyPolygon(
    2597           0 :                                     rPropertyHolders.Current().getClipPolyPolygon());
    2598             : 
    2599           0 :                                 aClipPolyPolygon.transform(aTransform);
    2600           0 :                                 HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders);
    2601             :                             }
    2602             :                         }
    2603             :                     }
    2604             : 
    2605           0 :                     break;
    2606             :                 }
    2607             :                 case META_LINECOLOR_ACTION :
    2608             :                 {
    2609             :                     /** CHECKED, WORKS WELL */
    2610          12 :                     const MetaLineColorAction* pA = (const MetaLineColorAction*)pAction;
    2611          12 :                     const bool bActive(pA->IsSetting());
    2612             : 
    2613          12 :                     rPropertyHolders.Current().setLineColorActive(bActive);
    2614          12 :                     if(bActive)
    2615           0 :                         rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor());
    2616             : 
    2617          12 :                     break;
    2618             :                 }
    2619             :                 case META_FILLCOLOR_ACTION :
    2620             :                 {
    2621             :                     /** CHECKED, WORKS WELL */
    2622           7 :                     const MetaFillColorAction* pA = (const MetaFillColorAction*)pAction;
    2623           7 :                     const bool bActive(pA->IsSetting());
    2624             : 
    2625           7 :                     rPropertyHolders.Current().setFillColorActive(bActive);
    2626           7 :                     if(bActive)
    2627           7 :                         rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor());
    2628             : 
    2629           7 :                     break;
    2630             :                 }
    2631             :                 case META_TEXTCOLOR_ACTION :
    2632             :                 {
    2633             :                     /** SIMPLE, DONE */
    2634           0 :                     const MetaTextColorAction* pA = (const MetaTextColorAction*)pAction;
    2635           0 :                     const bool bActivate(COL_TRANSPARENT != pA->GetColor().GetColor());
    2636             : 
    2637           0 :                     rPropertyHolders.Current().setTextColorActive(bActivate);
    2638           0 :                     rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor());
    2639             : 
    2640           0 :                     break;
    2641             :                 }
    2642             :                 case META_TEXTFILLCOLOR_ACTION :
    2643             :                 {
    2644             :                     /** SIMPLE, DONE */
    2645           0 :                     const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*)pAction;
    2646           0 :                     const bool bWithColorArgument(pA->IsSetting());
    2647             : 
    2648           0 :                     if(bWithColorArgument)
    2649             :                     {
    2650             :                         // emulate OutputDevice::SetTextFillColor(...) WITH argument
    2651           0 :                         const Color& rFontFillColor = pA->GetColor();
    2652           0 :                         rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
    2653           0 :                         rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
    2654             :                     }
    2655             :                     else
    2656             :                     {
    2657             :                         // emulate SetFillColor() <- NO argument (!)
    2658           0 :                         rPropertyHolders.Current().setTextFillColorActive(false);
    2659             :                     }
    2660             : 
    2661           0 :                     break;
    2662             :                 }
    2663             :                 case META_TEXTALIGN_ACTION :
    2664             :                 {
    2665             :                     /** SIMPLE, DONE */
    2666           0 :                     const MetaTextAlignAction* pA = (const MetaTextAlignAction*)pAction;
    2667           0 :                     const TextAlign aNewTextAlign = pA->GetTextAlign();
    2668             : 
    2669             :                     // TextAlign is applied to the current font (as in
    2670             :                     // OutputDevice::SetTextAlign which would be used when
    2671             :                     // playing the Metafile)
    2672           0 :                     if(rPropertyHolders.Current().getFont().GetAlign() != aNewTextAlign)
    2673             :                     {
    2674           0 :                         Font aNewFont(rPropertyHolders.Current().getFont());
    2675           0 :                         aNewFont.SetAlign(aNewTextAlign);
    2676           0 :                         rPropertyHolders.Current().setFont(aNewFont);
    2677             :                     }
    2678             : 
    2679           0 :                     break;
    2680             :                 }
    2681             :                 case META_MAPMODE_ACTION :
    2682             :                 {
    2683             :                     /** CHECKED, WORKS WELL */
    2684             :                     // the most necessary MapMode to be interpreted is MAP_RELATIVE,
    2685             :                     // but also the others may occur. Even not yet supported ones
    2686             :                     // may need to be added here later
    2687           0 :                     const MetaMapModeAction* pA = (const MetaMapModeAction*)pAction;
    2688           0 :                     const MapMode& rMapMode = pA->GetMapMode();
    2689           0 :                     basegfx::B2DHomMatrix aMapping;
    2690             : 
    2691           0 :                     if(MAP_RELATIVE == rMapMode.GetMapUnit())
    2692             :                     {
    2693           0 :                         aMapping = getTransformFromMapMode(rMapMode);
    2694             :                     }
    2695             :                     else
    2696             :                     {
    2697           0 :                         switch(rMapMode.GetMapUnit())
    2698             :                         {
    2699             :                             case MAP_100TH_MM :
    2700             :                             {
    2701           0 :                                 if(MAP_TWIP == rPropertyHolders.Current().getMapUnit())
    2702             :                                 {
    2703             :                                     // MAP_TWIP -> MAP_100TH_MM
    2704           0 :                                     const double fTwipTo100thMm(127.0 / 72.0);
    2705           0 :                                     aMapping.scale(fTwipTo100thMm, fTwipTo100thMm);
    2706             :                                 }
    2707           0 :                                 break;
    2708             :                             }
    2709             :                             case MAP_TWIP :
    2710             :                             {
    2711           0 :                                 if(MAP_100TH_MM == rPropertyHolders.Current().getMapUnit())
    2712             :                                 {
    2713             :                                     // MAP_100TH_MM -> MAP_TWIP
    2714           0 :                                     const double f100thMmToTwip(72.0 / 127.0);
    2715           0 :                                     aMapping.scale(f100thMmToTwip, f100thMmToTwip);
    2716             :                                 }
    2717           0 :                                 break;
    2718             :                             }
    2719             :                             default :
    2720             :                             {
    2721             :                                 OSL_FAIL("interpretMetafile: META_MAPMODE_ACTION with unsupported MapUnit (!)");
    2722           0 :                                 break;
    2723             :                             }
    2724             :                         }
    2725             : 
    2726           0 :                         aMapping = getTransformFromMapMode(rMapMode) * aMapping;
    2727           0 :                         rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit());
    2728             :                     }
    2729             : 
    2730           0 :                     if(!aMapping.isIdentity())
    2731             :                     {
    2732           0 :                         aMapping = aMapping * rPropertyHolders.Current().getTransformation();
    2733           0 :                         rPropertyHolders.Current().setTransformation(aMapping);
    2734             :                     }
    2735             : 
    2736           0 :                     break;
    2737             :                 }
    2738             :                 case META_FONT_ACTION :
    2739             :                 {
    2740             :                     /** SIMPLE, DONE */
    2741           0 :                     const MetaFontAction* pA = (const MetaFontAction*)pAction;
    2742           0 :                     rPropertyHolders.Current().setFont(pA->GetFont());
    2743           0 :                     Size aFontSize(pA->GetFont().GetSize());
    2744             : 
    2745           0 :                     if(0 == aFontSize.Height())
    2746             :                     {
    2747             :                         // this should not happen but i got Metafiles where this was the
    2748             :                         // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont())
    2749           0 :                         Font aCorrectedFont(pA->GetFont());
    2750             : 
    2751             :                         // guess 16 pixel (as in VCL)
    2752           0 :                         aFontSize = Size(0, 16);
    2753             : 
    2754             :                         // convert to target MapUnit if not pixels
    2755           0 :                         aFontSize = Application::GetDefaultDevice()->LogicToLogic(
    2756           0 :                             aFontSize, MAP_PIXEL, rPropertyHolders.Current().getMapUnit());
    2757             : 
    2758           0 :                         aCorrectedFont.SetSize(aFontSize);
    2759           0 :                         rPropertyHolders.Current().setFont(aCorrectedFont);
    2760             :                     }
    2761             : 
    2762             :                     // older Metafiles have no META_TEXTCOLOR_ACTION which defines
    2763             :                     // the FontColor now, so use the Font's color when not transparent
    2764           0 :                     const Color& rFontColor = pA->GetFont().GetColor();
    2765           0 :                     const bool bActivate(COL_TRANSPARENT != rFontColor.GetColor());
    2766             : 
    2767           0 :                     if(bActivate)
    2768             :                     {
    2769           0 :                         rPropertyHolders.Current().setTextColor(rFontColor.getBColor());
    2770             :                     }
    2771             : 
    2772             :                     // caution: do NOT decativate here on transparet, see
    2773             :                     // OutputDevice::SetFont(..) for more info
    2774             :                     // rPropertyHolders.Current().setTextColorActive(bActivate);
    2775             : 
    2776             :                     // for fill color emulate a MetaTextFillColorAction with !transparent as bool,
    2777             :                     // see OutputDevice::SetFont(..) the if(mpMetaFile) case
    2778           0 :                     if(bActivate)
    2779             :                     {
    2780           0 :                         const Color& rFontFillColor = pA->GetFont().GetFillColor();
    2781           0 :                         rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
    2782           0 :                         rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
    2783             :                     }
    2784             :                     else
    2785             :                     {
    2786           0 :                         rPropertyHolders.Current().setTextFillColorActive(false);
    2787             :                     }
    2788             : 
    2789             :                     break;
    2790             :                 }
    2791             :                 case META_PUSH_ACTION :
    2792             :                 {
    2793             :                     /** CHECKED, WORKS WELL */
    2794          20 :                     const MetaPushAction* pA = (const MetaPushAction*)pAction;
    2795          20 :                     rPropertyHolders.Push(pA->GetFlags());
    2796             : 
    2797          20 :                     break;
    2798             :                 }
    2799             :                 case META_POP_ACTION :
    2800             :                 {
    2801             :                     /** CHECKED, WORKS WELL */
    2802          20 :                     const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION);
    2803          20 :                     const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP);
    2804             : 
    2805          20 :                     if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
    2806             :                     {
    2807             :                         // end evtl. clipping
    2808           5 :                         const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
    2809             : 
    2810           5 :                         HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
    2811             :                     }
    2812             : 
    2813          20 :                     if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
    2814             :                     {
    2815             :                         // end evtl. RasterOp
    2816           0 :                         HandleNewRasterOp(ROP_OVERPAINT, rTargetHolders, rPropertyHolders);
    2817             :                     }
    2818             : 
    2819          20 :                     rPropertyHolders.Pop();
    2820             : 
    2821          20 :                     if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
    2822             :                     {
    2823             :                         // start evtl. RasterOp
    2824           0 :                         HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders);
    2825             :                     }
    2826             : 
    2827          20 :                     if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
    2828             :                     {
    2829             :                         // start evtl. clipping
    2830             :                         HandleNewClipRegion(
    2831           0 :                             rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders);
    2832             :                     }
    2833             : 
    2834          20 :                     break;
    2835             :                 }
    2836             :                 case META_RASTEROP_ACTION :
    2837             :                 {
    2838             :                     /** CHECKED, WORKS WELL */
    2839           9 :                     const MetaRasterOpAction* pA = (const MetaRasterOpAction*)pAction;
    2840           9 :                     const RasterOp aRasterOp = pA->GetRasterOp();
    2841             : 
    2842           9 :                     HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders);
    2843             : 
    2844           9 :                     break;
    2845             :                 }
    2846             :                 case META_TRANSPARENT_ACTION :
    2847             :                 {
    2848             :                     /** CHECKED, WORKS WELL */
    2849           0 :                     const MetaTransparentAction* pA = (const MetaTransparentAction*)pAction;
    2850           0 :                     const basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
    2851             : 
    2852           0 :                     if(aOutline.count())
    2853             :                     {
    2854           0 :                         const sal_uInt16 nTransparence(pA->GetTransparence());
    2855             : 
    2856           0 :                         if(0 == nTransparence)
    2857             :                         {
    2858             :                             // not transparent
    2859           0 :                             createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    2860             :                         }
    2861           0 :                         else if(nTransparence >= 100)
    2862             :                         {
    2863             :                             // fully or more than transparent
    2864             :                         }
    2865             :                         else
    2866             :                         {
    2867             :                             // transparent. Create new target
    2868           0 :                             rTargetHolders.Push();
    2869             : 
    2870             :                             // create primitives there and get them
    2871           0 :                             createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
    2872             :                             const drawinglayer::primitive2d::Primitive2DSequence aSubContent(
    2873           0 :                                 rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()));
    2874             : 
    2875             :                             // back to old target
    2876           0 :                             rTargetHolders.Pop();
    2877             : 
    2878           0 :                             if(aSubContent.hasElements())
    2879             :                             {
    2880           0 :                                 rTargetHolders.Current().append(
    2881             :                                     new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
    2882             :                                         aSubContent,
    2883           0 :                                         nTransparence * 0.01));
    2884           0 :                             }
    2885             :                         }
    2886             :                     }
    2887             : 
    2888           0 :                     break;
    2889             :                 }
    2890             :                 case META_EPS_ACTION :
    2891             :                 {
    2892             :                     /** CHECKED, WORKS WELL */
    2893             :                     // To support this action, i have added a EpsPrimitive2D which will
    2894             :                     // by default decompose to the Metafile replacement data. To support
    2895             :                     // this EPS on screen, the renderer visualizing this has to support
    2896             :                     // that primitive and visualize the Eps file (e.g. printing)
    2897           0 :                     const MetaEPSAction* pA = (const MetaEPSAction*)pAction;
    2898           0 :                     const Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
    2899             : 
    2900           0 :                     if(!aRectangle.IsEmpty())
    2901             :                     {
    2902             :                         // create object transform
    2903           0 :                         basegfx::B2DHomMatrix aObjectTransform;
    2904             : 
    2905           0 :                         aObjectTransform.set(0, 0, aRectangle.GetWidth());
    2906           0 :                         aObjectTransform.set(1, 1, aRectangle.GetHeight());
    2907           0 :                         aObjectTransform.set(0, 2, aRectangle.Left());
    2908           0 :                         aObjectTransform.set(1, 2, aRectangle.Top());
    2909             : 
    2910             :                         // add current transformation
    2911           0 :                         aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
    2912             : 
    2913             :                         // embed using EpsPrimitive
    2914           0 :                         rTargetHolders.Current().append(
    2915             :                             new drawinglayer::primitive2d::EpsPrimitive2D(
    2916             :                                 aObjectTransform,
    2917             :                                 pA->GetLink(),
    2918           0 :                                 pA->GetSubstitute()));
    2919             :                     }
    2920             : 
    2921             :                     break;
    2922             :                 }
    2923             :                 case META_REFPOINT_ACTION :
    2924             :                 {
    2925             :                     /** SIMPLE, DONE */
    2926             :                     // only used for hatch and line pattern offsets, pretty much no longer
    2927             :                     // supported today
    2928             :                     // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction;
    2929           0 :                     break;
    2930             :                 }
    2931             :                 case META_TEXTLINECOLOR_ACTION :
    2932             :                 {
    2933             :                     /** SIMPLE, DONE */
    2934           0 :                     const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*)pAction;
    2935           0 :                     const bool bActive(pA->IsSetting());
    2936             : 
    2937           0 :                     rPropertyHolders.Current().setTextLineColorActive(bActive);
    2938           0 :                     if(bActive)
    2939           0 :                         rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor());
    2940             : 
    2941           0 :                     break;
    2942             :                 }
    2943             :                 case META_TEXTLINE_ACTION :
    2944             :                 {
    2945             :                     /** CHECKED, WORKS WELL */
    2946             :                     // actually creates overline, underline and strikeouts, so
    2947             :                     // these should be isolated from TextDecoratedPortionPrimitive2D
    2948             :                     // to own primitives. Done, available now.
    2949             :                     //
    2950             :                     // This Metaaction seems not to be used (was not used in any
    2951             :                     // checked files). It's used in combination with the current
    2952             :                     // Font.
    2953           0 :                     const MetaTextLineAction* pA = (const MetaTextLineAction*)pAction;
    2954             : 
    2955             :                     proccessMetaTextLineAction(
    2956             :                         *pA,
    2957           0 :                         rTargetHolders.Current(),
    2958           0 :                         rPropertyHolders.Current());
    2959             : 
    2960           0 :                     break;
    2961             :                 }
    2962             :                 case META_FLOATTRANSPARENT_ACTION :
    2963             :                 {
    2964             :                     /** CHECKED, WORKS WELL */
    2965           0 :                     const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)pAction;
    2966           0 :                     const Rectangle aTargetRectangle(pA->GetPoint(), pA->GetSize());
    2967             : 
    2968           0 :                     if(!aTargetRectangle.IsEmpty())
    2969             :                     {
    2970           0 :                         const GDIMetaFile& rContent = pA->GetGDIMetaFile();
    2971             : 
    2972           0 :                         if(rContent.GetActionSize())
    2973             :                         {
    2974             :                             // create the sub-content with no embedding specific to the
    2975             :                             // sub-metafile, this seems not to be used.
    2976           0 :                             drawinglayer::primitive2d::Primitive2DSequence xSubContent;
    2977             :                             {
    2978           0 :                                 rTargetHolders.Push();
    2979             :                                 // #i# for sub-Mteafile contents, do start with new, default render state
    2980           0 :                                 rPropertyHolders.PushDefault();
    2981           0 :                                 interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation);
    2982           0 :                                 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
    2983           0 :                                 rPropertyHolders.Pop();
    2984           0 :                                 rTargetHolders.Pop();
    2985             :                             }
    2986             : 
    2987           0 :                             if(xSubContent.hasElements())
    2988             :                             {
    2989             :                                 // check if gradient is a real gradient
    2990           0 :                                 const Gradient& rGradient = pA->GetGradient();
    2991           0 :                                 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
    2992             : 
    2993           0 :                                 if(aAttribute.getStartColor() == aAttribute.getEndColor())
    2994             :                                 {
    2995             :                                     // not really a gradient; create UnifiedTransparencePrimitive2D
    2996           0 :                                     rTargetHolders.Current().append(
    2997             :                                         new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
    2998             :                                             xSubContent,
    2999           0 :                                             aAttribute.getStartColor().luminance()));
    3000             :                                 }
    3001             :                                 else
    3002             :                                 {
    3003             :                                     // really a gradient. Create gradient sub-content (with correct scaling)
    3004             :                                     basegfx::B2DRange aRange(
    3005           0 :                                         aTargetRectangle.Left(), aTargetRectangle.Top(),
    3006           0 :                                         aTargetRectangle.Right(), aTargetRectangle.Bottom());
    3007           0 :                                     aRange.transform(rPropertyHolders.Current().getTransformation());
    3008             : 
    3009             :                                     // prepare gradient for transparent content
    3010             :                                     const drawinglayer::primitive2d::Primitive2DReference xTransparence(
    3011             :                                         new drawinglayer::primitive2d::FillGradientPrimitive2D(
    3012             :                                             aRange,
    3013           0 :                                             aAttribute));
    3014             : 
    3015             :                                     // create transparence primitive
    3016           0 :                                     rTargetHolders.Current().append(
    3017             :                                         new drawinglayer::primitive2d::TransparencePrimitive2D(
    3018             :                                             xSubContent,
    3019           0 :                                             drawinglayer::primitive2d::Primitive2DSequence(&xTransparence, 1)));
    3020           0 :                                 }
    3021           0 :                             }
    3022             :                         }
    3023             :                     }
    3024             : 
    3025             :                     break;
    3026             :                 }
    3027             :                 case META_GRADIENTEX_ACTION :
    3028             :                 {
    3029             :                     /** SIMPLE, DONE */
    3030             :                     // This is only a data holder which is interpreted inside comment actions,
    3031             :                     // see META_COMMENT_ACTION for more info
    3032             :                     // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction;
    3033           0 :                     break;
    3034             :                 }
    3035             :                 case META_LAYOUTMODE_ACTION :
    3036             :                 {
    3037             :                     /** SIMPLE, DONE */
    3038           0 :                     const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*)pAction;
    3039           0 :                     rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode());
    3040           0 :                     break;
    3041             :                 }
    3042             :                 case META_TEXTLANGUAGE_ACTION :
    3043             :                 {
    3044             :                     /** SIMPLE, DONE */
    3045           0 :                     const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*)pAction;
    3046           0 :                     rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage());
    3047           0 :                     break;
    3048             :                 }
    3049             :                 case META_OVERLINECOLOR_ACTION :
    3050             :                 {
    3051             :                     /** SIMPLE, DONE */
    3052           0 :                     const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*)pAction;
    3053           0 :                     const bool bActive(pA->IsSetting());
    3054             : 
    3055           0 :                     rPropertyHolders.Current().setOverlineColorActive(bActive);
    3056           0 :                     if(bActive)
    3057           0 :                         rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor());
    3058             : 
    3059           0 :                     break;
    3060             :                 }
    3061             :                 case META_COMMENT_ACTION :
    3062             :                 {
    3063             :                     /** CHECKED, WORKS WELL */
    3064             :                     // I already implemented
    3065             :                     //     XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END
    3066             :                     //     XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END,
    3067             :                     // but opted to remove these again; it works well without them
    3068             :                     // and makes the code less dependent from those Metafile Add-Ons
    3069           0 :                     const MetaCommentAction* pA = (const MetaCommentAction*)pAction;
    3070             : 
    3071           0 :                     if (pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")))
    3072             :                     {
    3073             :                         // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the
    3074             :                         // pure recorded paint of the gradients uses the XOR paint functionality
    3075             :                         // ('trick'). This is (and will be) broblematic with AntAliasing, so it's
    3076             :                         // better to use this info
    3077           0 :                         const MetaGradientExAction* pMetaGradientExAction = 0;
    3078           0 :                         bool bDone(false);
    3079           0 :                         sal_uInt32 b(nAction + 1);
    3080             : 
    3081           0 :                         for(; !bDone && b < nCount; b++)
    3082             :                         {
    3083           0 :                             pAction = rMetaFile.GetAction(b);
    3084             : 
    3085           0 :                             if(META_GRADIENTEX_ACTION == pAction->GetType())
    3086             :                             {
    3087           0 :                                 pMetaGradientExAction = (const MetaGradientExAction*)pAction;
    3088             :                             }
    3089           0 :                             else if(META_COMMENT_ACTION == pAction->GetType())
    3090             :                             {
    3091           0 :                                 if (((const MetaCommentAction*)pAction)->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")))
    3092             :                                 {
    3093           0 :                                     bDone = true;
    3094             :                                 }
    3095             :                             }
    3096             :                         }
    3097             : 
    3098           0 :                         if(bDone && pMetaGradientExAction)
    3099             :                         {
    3100             :                             // consume actions and skip forward
    3101           0 :                             nAction = b - 1;
    3102             : 
    3103             :                             // get geometry data
    3104           0 :                             basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon());
    3105             : 
    3106           0 :                             if(aPolyPolygon.count())
    3107             :                             {
    3108             :                                 // transform geometry
    3109           0 :                                 aPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
    3110             : 
    3111             :                                 // get and check if gradient is a real gradient
    3112           0 :                                 const Gradient& rGradient = pMetaGradientExAction->GetGradient();
    3113           0 :                                 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
    3114             : 
    3115           0 :                                 if(aAttribute.getStartColor() == aAttribute.getEndColor())
    3116             :                                 {
    3117             :                                     // not really a gradient
    3118           0 :                                     rTargetHolders.Current().append(
    3119             :                                         new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
    3120             :                                             aPolyPolygon,
    3121           0 :                                             aAttribute.getStartColor()));
    3122             :                                 }
    3123             :                                 else
    3124             :                                 {
    3125             :                                     // really a gradient
    3126           0 :                                     rTargetHolders.Current().append(
    3127             :                                         new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D(
    3128             :                                             aPolyPolygon,
    3129           0 :                                             aAttribute));
    3130           0 :                                 }
    3131           0 :                             }
    3132             :                         }
    3133             :                     }
    3134             : 
    3135           0 :                     break;
    3136             :                 }
    3137             :                 default:
    3138             :                 {
    3139             :                     OSL_FAIL("Unknown MetaFile Action (!)");
    3140           0 :                     break;
    3141             :                 }
    3142             :             }
    3143             :         }
    3144           1 :     }
    3145             : } // end of anonymous namespace
    3146             : 
    3147             : //////////////////////////////////////////////////////////////////////////////
    3148             : 
    3149             : namespace drawinglayer
    3150             : {
    3151             :     namespace primitive2d
    3152             :     {
    3153           1 :         Primitive2DSequence MetafilePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
    3154             :         {
    3155             :             // prepare target and porperties; each will have one default entry
    3156           1 :             TargetHolders aTargetHolders;
    3157           1 :             PropertyHolders aPropertyHolders;
    3158             : 
    3159             :             // set target MapUnit at Properties
    3160           1 :             aPropertyHolders.Current().setMapUnit(getMetaFile().GetPrefMapMode().GetMapUnit());
    3161             : 
    3162             :             // interpret the Metafile
    3163           1 :             interpretMetafile(getMetaFile(), aTargetHolders, aPropertyHolders, rViewInformation);
    3164             : 
    3165             :             // get the content. There should be ony one target, as in the start condition,
    3166             :             // but iterating will be the right thing to do when some push/pop is not closed
    3167           1 :             Primitive2DSequence xRetval;
    3168             : 
    3169           2 :             while(aTargetHolders.size() > 1)
    3170             :             {
    3171             :                 appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
    3172           0 :                     aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
    3173           0 :                 aTargetHolders.Pop();
    3174             :             }
    3175             : 
    3176             :             appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
    3177           1 :                 aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
    3178             : 
    3179           1 :             if(xRetval.hasElements())
    3180             :             {
    3181             :                 // get target size
    3182           1 :                 const Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize());
    3183             : 
    3184             :                 // create transformation
    3185           1 :                 basegfx::B2DHomMatrix aAdaptedTransform;
    3186             : 
    3187           1 :                 aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top());
    3188             :                 aAdaptedTransform.scale(
    3189           2 :                     aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0,
    3190           3 :                     aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0);
    3191           1 :                 aAdaptedTransform = getTransform() * aAdaptedTransform;
    3192             : 
    3193             :                 // embed to target transformation
    3194             :                 const Primitive2DReference aEmbeddedTransform(
    3195             :                     new TransformPrimitive2D(
    3196             :                         aAdaptedTransform,
    3197           1 :                         xRetval));
    3198             : 
    3199           1 :                 xRetval = Primitive2DSequence(&aEmbeddedTransform, 1);
    3200             :             }
    3201             : 
    3202           1 :             return xRetval;
    3203             :         }
    3204             : 
    3205           1 :         MetafilePrimitive2D::MetafilePrimitive2D(
    3206             :             const basegfx::B2DHomMatrix& rMetaFileTransform,
    3207             :             const GDIMetaFile& rMetaFile)
    3208             :         :   BufferedDecompositionPrimitive2D(),
    3209             :             maMetaFileTransform(rMetaFileTransform),
    3210           1 :             maMetaFile(rMetaFile)
    3211             :         {
    3212           1 :         }
    3213             : 
    3214           0 :         bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
    3215             :         {
    3216           0 :             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
    3217             :             {
    3218           0 :                 const MetafilePrimitive2D& rCompare = (MetafilePrimitive2D&)rPrimitive;
    3219             : 
    3220           0 :                 return (getTransform() == rCompare.getTransform()
    3221           0 :                     && getMetaFile() == rCompare.getMetaFile());
    3222             :             }
    3223             : 
    3224           0 :             return false;
    3225             :         }
    3226             : 
    3227           0 :         basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
    3228             :         {
    3229             :             // use own implementation to quickly answer the getB2DRange question. The
    3230             :             // MetafilePrimitive2D assumes that all geometry is inside of the shape. If
    3231             :             // this is not the case (i have already seen some wrong Metafiles) it should
    3232             :             // be embedded to a MaskPrimitive2D
    3233           0 :             basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
    3234           0 :             aRetval.transform(getTransform());
    3235             : 
    3236           0 :             return aRetval;
    3237             :         }
    3238             : 
    3239             :         // provide unique ID
    3240           2 :         ImplPrimitrive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D)
    3241             : 
    3242             :     } // end of namespace primitive2d
    3243             : } // end of namespace drawinglayer
    3244             : 
    3245             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10