LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/drawinglayer/source/primitive2d - metafileprimitive2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 427 1180 36.2 %
Date: 2013-07-09 Functions: 80 100 80.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10