LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - metafileprimitive2d.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 554 1182 46.9 %
Date: 2014-11-03 Functions: 85 100 85.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10