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

Generated by: LCOV version 1.11