LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/processor2d - vclmetafileprocessor2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 252 713 35.3 %
Date: 2012-12-27 Functions: 13 16 81.2 %
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/processor2d/vclmetafileprocessor2d.hxx>
      21             : #include <tools/gen.hxx>
      22             : #include <vcl/virdev.hxx>
      23             : #include <vcl/gdimtf.hxx>
      24             : #include <vcl/gradient.hxx>
      25             : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
      26             : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
      27             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      28             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      29             : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
      30             : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
      31             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      32             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      33             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      34             : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
      35             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      36             : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
      37             : #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
      38             : #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
      39             : #include <tools/stream.hxx>
      40             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      41             : #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
      42             : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
      43             : #include <vcl/graphictools.hxx>
      44             : #include <vcl/metaact.hxx>
      45             : #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
      46             : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
      47             : #include <comphelper/processfactory.hxx>
      48             : #include <rtl/ustring.hxx>
      49             : #include <com/sun/star/i18n/BreakIterator.hpp>
      50             : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
      51             : #include <com/sun/star/i18n/WordType.hpp>
      52             : #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
      53             : #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
      54             : #include <basegfx/polygon/b2dpolygontools.hxx>
      55             : #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
      56             : #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
      57             : #include <basegfx/polygon/b2dlinegeometry.hxx>
      58             : 
      59             : //////////////////////////////////////////////////////////////////////////////
      60             : // for PDFExtOutDevData Graphic support
      61             : 
      62             : #include <vcl/graph.hxx>
      63             : #include <vcl/svapp.hxx>
      64             : #include <toolkit/helper/formpdfexport.hxx>
      65             : 
      66             : //////////////////////////////////////////////////////////////////////////////
      67             : // for Control printing
      68             : 
      69             : #include <com/sun/star/beans/XPropertySet.hpp>
      70             : 
      71             : //////////////////////////////////////////////////////////////////////////////
      72             : // for StructureTagPrimitive support in sd's unomodel.cxx
      73             : 
      74             : #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
      75             : 
      76             : //////////////////////////////////////////////////////////////////////////////
      77             : 
      78             : using namespace com::sun::star;
      79             : 
      80             : //////////////////////////////////////////////////////////////////////////////
      81             : // #112245# definition for maximum allowed point count due to Metafile target.
      82             : // To be on the safe side with the old tools polygon, use slightly less then
      83             : // the theoretical maximum (bad experiences with tools polygon)
      84             : 
      85             : #define MAX_POLYGON_POINT_COUNT_METAFILE    (0x0000fff0)
      86             : 
      87             : //////////////////////////////////////////////////////////////////////////////
      88             : 
      89             : namespace
      90             : {
      91             :     // #112245# helper to split line polygon in half
      92           0 :     void splitLinePolygon(
      93             :         const basegfx::B2DPolygon& rBasePolygon,
      94             :         basegfx::B2DPolygon& o_aLeft,
      95             :         basegfx::B2DPolygon& o_aRight)
      96             :     {
      97           0 :         const sal_uInt32 nCount(rBasePolygon.count());
      98             : 
      99           0 :         if(nCount)
     100             :         {
     101           0 :             const sal_uInt32 nHalfCount((nCount - 1) >> 1);
     102             : 
     103           0 :             o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
     104           0 :             o_aLeft.setClosed(false);
     105             : 
     106           0 :             o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
     107           0 :             o_aRight.setClosed(false);
     108             : 
     109           0 :             if(rBasePolygon.isClosed())
     110             :             {
     111           0 :                 o_aRight.append(rBasePolygon.getB2DPoint(0));
     112             : 
     113           0 :                 if(rBasePolygon.areControlPointsUsed())
     114             :                 {
     115             :                     o_aRight.setControlPoints(
     116           0 :                         o_aRight.count() - 1,
     117             :                         rBasePolygon.getPrevControlPoint(0),
     118           0 :                         rBasePolygon.getNextControlPoint(0));
     119             :                 }
     120             :             }
     121             :         }
     122             :         else
     123             :         {
     124           0 :             o_aLeft.clear();
     125           0 :             o_aRight.clear();
     126             :         }
     127           0 :     }
     128             : 
     129             :     // #112245# helper to evtl. split filled polygons to maximum metafile point count
     130          19 :     bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
     131             :     {
     132          19 :         bool bRetval(false);
     133          19 :         const sal_uInt32 nPolyCount(rPolyPolygon.count());
     134             : 
     135          19 :         if(nPolyCount)
     136             :         {
     137          19 :             basegfx::B2DPolyPolygon aSplitted;
     138             : 
     139          46 :             for(sal_uInt32 a(0); a < nPolyCount; a++)
     140             :             {
     141          27 :                 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
     142          27 :                 const sal_uInt32 nPointCount(aCandidate.count());
     143          27 :                 bool bNeedToSplit(false);
     144             : 
     145          27 :                 if(aCandidate.areControlPointsUsed())
     146             :                 {
     147             :                     // compare with the maximum for bezier curved polygons
     148          16 :                     bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
     149             :                 }
     150             :                 else
     151             :                 {
     152             :                     // compare with the maximum for simple point polygons
     153          11 :                     bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
     154             :                 }
     155             : 
     156          27 :                 if(bNeedToSplit)
     157             :                 {
     158             :                     // need to split the partial polygon
     159           0 :                     const basegfx::B2DRange aRange(aCandidate.getB2DRange());
     160           0 :                     const basegfx::B2DPoint aCenter(aRange.getCenter());
     161             : 
     162           0 :                     if(aRange.getWidth() > aRange.getHeight())
     163             :                     {
     164             :                         // clip in left and right
     165             :                         const basegfx::B2DPolyPolygon aLeft(
     166             :                             basegfx::tools::clipPolygonOnParallelAxis(
     167             :                                 aCandidate,
     168             :                                 false,
     169             :                                 true,
     170             :                                 aCenter.getX(),
     171           0 :                                 false));
     172             :                         const basegfx::B2DPolyPolygon aRight(
     173             :                             basegfx::tools::clipPolygonOnParallelAxis(
     174             :                                 aCandidate,
     175             :                                 false,
     176             :                                 false,
     177             :                                 aCenter.getX(),
     178           0 :                                 false));
     179             : 
     180           0 :                         aSplitted.append(aLeft);
     181           0 :                         aSplitted.append(aRight);
     182             :                     }
     183             :                     else
     184             :                     {
     185             :                         // clip in top and bottom
     186             :                         const basegfx::B2DPolyPolygon aTop(
     187             :                             basegfx::tools::clipPolygonOnParallelAxis(
     188             :                                 aCandidate,
     189             :                                 true,
     190             :                                 true,
     191             :                                 aCenter.getY(),
     192           0 :                                 false));
     193             :                         const basegfx::B2DPolyPolygon aBottom(
     194             :                             basegfx::tools::clipPolygonOnParallelAxis(
     195             :                                 aCandidate,
     196             :                                 true,
     197             :                                 false,
     198             :                                 aCenter.getY(),
     199           0 :                                 false));
     200             : 
     201           0 :                         aSplitted.append(aTop);
     202           0 :                         aSplitted.append(aBottom);
     203           0 :                     }
     204             :                 }
     205             :                 else
     206             :                 {
     207          27 :                     aSplitted.append(aCandidate);
     208             :                 }
     209          27 :             }
     210             : 
     211          19 :             if(aSplitted.count() != nPolyCount)
     212             :             {
     213           0 :                 rPolyPolygon = aSplitted;
     214          19 :             }
     215             :         }
     216             : 
     217          19 :         return bRetval;
     218             :     }
     219             : 
     220             :     /** Filter input polypolygon for effectively empty sub-fills
     221             : 
     222             :         Needed to fix fdo#37559
     223             : 
     224             :         @param rPoly
     225             :         PolyPolygon to filter
     226             : 
     227             :         @return converted tools PolyPolygon, w/o one-point fills
     228             :      */
     229          19 :     PolyPolygon getFillPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly )
     230             :     {
     231             :         // filter input rPoly
     232          19 :         basegfx::B2DPolyPolygon aPoly;
     233          19 :         sal_uInt32 nCount(rPoly.count());
     234          46 :         for( sal_uInt32 i=0; i<nCount; ++i )
     235             :         {
     236          27 :             basegfx::B2DPolygon aCandidate(rPoly.getB2DPolygon(i));
     237          27 :             if( !aCandidate.isClosed() || aCandidate.count() > 1 )
     238          27 :                 aPoly.append(aCandidate);
     239          27 :         }
     240          19 :         return PolyPolygon(aPoly);
     241             :     }
     242             : 
     243             : } // end of anonymous namespace
     244             : 
     245             : //////////////////////////////////////////////////////////////////////////////
     246             : 
     247             : namespace drawinglayer
     248             : {
     249             :     namespace processor2d
     250             :     {
     251           0 :         Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
     252             :             const primitive2d::Primitive2DSequence& rContent,
     253             :             GDIMetaFile& o_rContentMetafile)
     254             :         {
     255             :             // Prepare VDev, MetaFile and connections
     256           0 :             OutputDevice* pLastOutputDevice = mpOutputDevice;
     257           0 :             GDIMetaFile* pLastMetafile = mpMetaFile;
     258           0 :             basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
     259             : 
     260             :             // transform primitive range with current transformation (e.g shadow offset)
     261           0 :             aPrimitiveRange.transform(maCurrentTransformation);
     262             : 
     263             :             const Rectangle aPrimitiveRectangle(
     264             :                 basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
     265           0 :                 basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
     266           0 :             VirtualDevice aContentVDev;
     267           0 :             MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
     268             : 
     269           0 :             mpOutputDevice = &aContentVDev;
     270           0 :             mpMetaFile = &o_rContentMetafile;
     271           0 :             aContentVDev.EnableOutput(false);
     272           0 :             aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
     273           0 :             o_rContentMetafile.Record(&aContentVDev);
     274           0 :             aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
     275           0 :             aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
     276           0 :             aContentVDev.SetFont(pLastOutputDevice->GetFont());
     277           0 :             aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
     278           0 :             aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
     279           0 :             aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
     280             : 
     281             :             // dump to MetaFile
     282           0 :             process(rContent);
     283             : 
     284             :             // cleanups
     285           0 :             o_rContentMetafile.Stop();
     286           0 :             o_rContentMetafile.WindStart();
     287           0 :             aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
     288           0 :             o_rContentMetafile.SetPrefMapMode(aNewMapMode);
     289           0 :             o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
     290           0 :             mpOutputDevice = pLastOutputDevice;
     291           0 :             mpMetaFile = pLastMetafile;
     292             : 
     293           0 :             return aPrimitiveRectangle;
     294             :         }
     295             : 
     296           0 :         void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
     297             :             Gradient& o_rVCLGradient,
     298             :             const attribute::FillGradientAttribute& rFiGrAtt,
     299             :             bool bIsTransparenceGradient)
     300             :         {
     301           0 :             if(bIsTransparenceGradient)
     302             :             {
     303             :                 // it's about transparence channel intensities (black/white), do not use color modifier
     304           0 :                 o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
     305           0 :                 o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
     306             :             }
     307             :             else
     308             :             {
     309             :                 // use color modifier to influence start/end color of gradient
     310           0 :                 o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
     311           0 :                 o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
     312             :             }
     313             : 
     314           0 :             o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
     315           0 :             o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
     316           0 :             o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
     317           0 :             o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
     318           0 :             o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
     319             : 
     320             :             // defaults for intensity; those were computed into the start/end colors already
     321           0 :             o_rVCLGradient.SetStartIntensity(100);
     322           0 :             o_rVCLGradient.SetEndIntensity(100);
     323             : 
     324           0 :             switch(rFiGrAtt.getStyle())
     325             :             {
     326             :                 default : // attribute::GRADIENTSTYLE_LINEAR :
     327             :                 {
     328           0 :                     o_rVCLGradient.SetStyle(GradientStyle_LINEAR);
     329           0 :                     break;
     330             :                 }
     331             :                 case attribute::GRADIENTSTYLE_AXIAL :
     332             :                 {
     333           0 :                     o_rVCLGradient.SetStyle(GradientStyle_AXIAL);
     334           0 :                     break;
     335             :                 }
     336             :                 case attribute::GRADIENTSTYLE_RADIAL :
     337             :                 {
     338           0 :                     o_rVCLGradient.SetStyle(GradientStyle_RADIAL);
     339           0 :                     break;
     340             :                 }
     341             :                 case attribute::GRADIENTSTYLE_ELLIPTICAL :
     342             :                 {
     343           0 :                     o_rVCLGradient.SetStyle(GradientStyle_ELLIPTICAL);
     344           0 :                     break;
     345             :                 }
     346             :                 case attribute::GRADIENTSTYLE_SQUARE :
     347             :                 {
     348           0 :                     o_rVCLGradient.SetStyle(GradientStyle_SQUARE);
     349           0 :                     break;
     350             :                 }
     351             :                 case attribute::GRADIENTSTYLE_RECT :
     352             :                 {
     353           0 :                     o_rVCLGradient.SetStyle(GradientStyle_RECT);
     354           0 :                     break;
     355             :                 }
     356             :             }
     357           0 :         }
     358             : 
     359          19 :         void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
     360             :         {
     361          19 :             if(pSvtGraphicFill && !mnSvtGraphicFillCount)
     362             :             {
     363          19 :                 SvMemoryStream aMemStm;
     364             : 
     365          19 :                 aMemStm << *pSvtGraphicFill;
     366          19 :                 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
     367          19 :                 mnSvtGraphicFillCount++;
     368             :             }
     369          19 :         }
     370             : 
     371          19 :         void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
     372             :         {
     373          19 :             if(pSvtGraphicFill && mnSvtGraphicFillCount)
     374             :             {
     375          19 :                 mnSvtGraphicFillCount--;
     376          19 :                 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
     377          19 :                 delete pSvtGraphicFill;
     378             :             }
     379          19 :         }
     380             : 
     381           8 :         SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
     382             :             const basegfx::B2DPolygon& rB2DPolygon,
     383             :             const basegfx::BColor* pColor,
     384             :             const attribute::LineAttribute* pLineAttribute,
     385             :             const attribute::StrokeAttribute* pStrokeAttribute,
     386             :             const attribute::LineStartEndAttribute* pStart,
     387             :             const attribute::LineStartEndAttribute* pEnd)
     388             :         {
     389           8 :             SvtGraphicStroke* pRetval = 0;
     390             : 
     391           8 :             if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
     392             :             {
     393           6 :                 basegfx::BColor aStrokeColor;
     394           6 :                 basegfx::B2DPolyPolygon aStartArrow;
     395           6 :                 basegfx::B2DPolyPolygon aEndArrow;
     396             : 
     397           6 :                 if(pColor)
     398             :                 {
     399           0 :                     aStrokeColor = *pColor;
     400             :                 }
     401           6 :                 else if(pLineAttribute)
     402             :                 {
     403           6 :                     aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
     404             :                 }
     405             : 
     406             :                 // It IS needed to record the stroke color at all in the metafile,
     407             :                 // SvtGraphicStroke has NO entry for stroke color(!)
     408           6 :                 mpOutputDevice->SetLineColor(Color(aStrokeColor));
     409             : 
     410           6 :                 if(!rB2DPolygon.isClosed())
     411             :                 {
     412           4 :                     double fPolyLength(0.0);
     413             : 
     414           4 :                     if(pStart && pStart->isActive())
     415             :                     {
     416           0 :                         fPolyLength = basegfx::tools::getLength(rB2DPolygon);
     417             : 
     418             :                         aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
     419           0 :                             rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
     420           0 :                             fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0);
     421             :                     }
     422             : 
     423           4 :                     if(pEnd && pEnd->isActive())
     424             :                     {
     425           1 :                         if(basegfx::fTools::equalZero(fPolyLength))
     426             :                         {
     427           1 :                             fPolyLength = basegfx::tools::getLength(rB2DPolygon);
     428             :                         }
     429             : 
     430             :                         aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
     431           1 :                             rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
     432           2 :                             fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0);
     433             :                     }
     434             :                 }
     435             : 
     436           6 :                 SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
     437           6 :                 SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
     438           6 :                 double fLineWidth(0.0);
     439           6 :                 double fMiterLength(0.0);
     440           6 :                 SvtGraphicStroke::DashArray aDashArray;
     441             : 
     442           6 :                 if(pLineAttribute)
     443             :                 {
     444             :                     // pre-fill fLineWidth
     445           6 :                     fLineWidth = pLineAttribute->getWidth();
     446             : 
     447             :                     // pre-fill fMiterLength
     448           6 :                     fMiterLength = fLineWidth;
     449             : 
     450             :                     // get Join
     451           6 :                     switch(pLineAttribute->getLineJoin())
     452             :                     {
     453             :                         default : // basegfx::B2DLINEJOIN_NONE :
     454             :                         {
     455           0 :                             eJoin = SvtGraphicStroke::joinNone;
     456           0 :                             break;
     457             :                         }
     458             :                         case basegfx::B2DLINEJOIN_BEVEL :
     459             :                         {
     460           0 :                             eJoin = SvtGraphicStroke::joinBevel;
     461           0 :                             break;
     462             :                         }
     463             :                         case basegfx::B2DLINEJOIN_MIDDLE :
     464             :                         case basegfx::B2DLINEJOIN_MITER :
     465             :                         {
     466           0 :                             eJoin = SvtGraphicStroke::joinMiter;
     467             :                             // ATM 15 degrees is assumed
     468           0 :                             fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
     469           0 :                             break;
     470             :                         }
     471             :                         case basegfx::B2DLINEJOIN_ROUND :
     472             :                         {
     473           6 :                             eJoin = SvtGraphicStroke::joinRound;
     474           6 :                             break;
     475             :                         }
     476             :                     }
     477             : 
     478             :                     // get stroke
     479           6 :                     switch(pLineAttribute->getLineCap())
     480             :                     {
     481             :                         default: /* com::sun::star::drawing::LineCap_BUTT */
     482             :                         {
     483           6 :                             eCap = SvtGraphicStroke::capButt;
     484           6 :                             break;
     485             :                         }
     486             :                         case com::sun::star::drawing::LineCap_ROUND:
     487             :                         {
     488           0 :                             eCap = SvtGraphicStroke::capRound;
     489           0 :                             break;
     490             :                         }
     491             :                         case com::sun::star::drawing::LineCap_SQUARE:
     492             :                         {
     493           0 :                             eCap = SvtGraphicStroke::capSquare;
     494           0 :                             break;
     495             :                         }
     496             :                     }
     497             :                 }
     498             : 
     499           6 :                 if(pStrokeAttribute)
     500             :                 {
     501             :                     // copy dash array
     502           6 :                     aDashArray = pStrokeAttribute->getDotDashArray();
     503             :                 }
     504             : 
     505             :                 // #i101734# apply current object transformation to created geometry.
     506             :                 // This is a partial fix. When a object transformation is used which
     507             :                 // e.g. contains a scaleX != scaleY, an unproportional scaling would
     508             :                 // have to be applied to the evtl. existing fat line. The current
     509             :                 // concept of PDF export and SvtGraphicStroke usage does simply not
     510             :                 // allow handling such definitions. The only clean way would be to
     511             :                 // add the transformation to SvtGraphicStroke and to handle it there
     512           6 :                 basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
     513             : 
     514           6 :                 aB2DPolygon.transform(maCurrentTransformation);
     515           6 :                 aStartArrow.transform(maCurrentTransformation);
     516           6 :                 aEndArrow.transform(maCurrentTransformation);
     517             : 
     518             :                 pRetval = new SvtGraphicStroke(
     519             :                     Polygon(aB2DPolygon),
     520             :                     PolyPolygon(aStartArrow),
     521             :                     PolyPolygon(aEndArrow),
     522             :                     mfCurrentUnifiedTransparence,
     523             :                     fLineWidth,
     524             :                     eCap,
     525             :                     eJoin,
     526             :                     fMiterLength,
     527           6 :                     aDashArray);
     528             :             }
     529             : 
     530           8 :             return pRetval;
     531             :         }
     532             : 
     533           8 :         void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
     534             :         {
     535           8 :             if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
     536             :             {
     537           6 :                 SvMemoryStream aMemStm;
     538             : 
     539           6 :                 aMemStm << *pSvtGraphicStroke;
     540           6 :                 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
     541           6 :                 mnSvtGraphicStrokeCount++;
     542             :             }
     543           8 :         }
     544             : 
     545           8 :         void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
     546             :         {
     547           8 :             if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
     548             :             {
     549           6 :                 mnSvtGraphicStrokeCount--;
     550           6 :                 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
     551           6 :                 delete pSvtGraphicStroke;
     552             :             }
     553           8 :         }
     554             : 
     555             :         // init static break iterator
     556          22 :         uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
     557             : 
     558          15 :         VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
     559             :         :   VclProcessor2D(rViewInformation, rOutDev),
     560          15 :             mpMetaFile(rOutDev.GetConnectMetaFile()),
     561             :             mnSvtGraphicFillCount(0),
     562             :             mnSvtGraphicStrokeCount(0),
     563             :             mfCurrentUnifiedTransparence(0.0),
     564          30 :             mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
     565             :         {
     566             :             OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
     567             :             // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
     568             :             // but only to ObjectTransformation. Do not change MapMode of destination.
     569          15 :             maCurrentTransformation = rViewInformation.getObjectTransformation();
     570          15 :         }
     571             : 
     572          30 :         VclMetafileProcessor2D::~VclMetafileProcessor2D()
     573             :         {
     574             :             // MapMode was not changed, no restore necessary
     575          30 :         }
     576             : 
     577             :         /***********************************************************************************************
     578             : 
     579             :             Support of MetaCommentActions in the VclMetafileProcessor2D
     580             :             Found MetaCommentActions and how they are supported:
     581             : 
     582             :             XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
     583             : 
     584             :             Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
     585             :             It is used in various exporters/importers to have direct access to the gradient before it
     586             :             is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
     587             :             the Metafile to SdrObject import creates it's gradient objects.
     588             :             Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
     589             :             map it back to the corresponding tools PolyPolygon and the Gradient and just call
     590             :             OutputDevice::DrawGradient which creates the necessary compatible actions.
     591             : 
     592             :             XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
     593             : 
     594             :             Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
     595             :             inside GDIMetaFile::Rotate, nothing to take care of here.
     596             :             The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
     597             :             with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
     598             :             XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
     599             :             to the comment action. A closing end token is created in the destructor.
     600             :             Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
     601             :             SdrRectObj.
     602             :             The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
     603             :             of filled objects, even simple colored polygons. It is added as extra information; the
     604             :             Metafile actions between the two tokens are interpreted as output generated from those
     605             :             fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
     606             :             actions.
     607             :             Even for XFillTransparenceItem it is used, thus it may need to be supported in
     608             :             UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
     609             :             Implemented for:
     610             :                 PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D,
     611             :                 PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
     612             :                 PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
     613             :                 PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
     614             :                 and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
     615             : 
     616             :             XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
     617             : 
     618             :             Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
     619             :             is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
     620             :             contained path accordingly.
     621             :             The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
     622             :             only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
     623             :             would hinder to make use of PolyPolygon strokes. I will need to add support at:
     624             :                 PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
     625             :                 PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
     626             :                 PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
     627             :             This can be done hierarchical, too.
     628             :             Okay, base implementation done based on those three primitives.
     629             : 
     630             :             FIELD_SEQ_BEGIN, FIELD_SEQ_END
     631             : 
     632             :             Used from slideshow for URLs, created from diverse SvxField implementations inside
     633             :             createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
     634             :             inside ImpEditEngine::Paint.
     635             :             Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
     636             :             text primitives (but is not limited to that). It contains the field type if special actions for the
     637             :             support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
     638             :             needed, it may be supported there.
     639             :             FIELD_SEQ_BEGIN;PageField
     640             :             FIELD_SEQ_END
     641             :             Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
     642             : 
     643             :             XTEXT
     644             : 
     645             :             XTEXT_EOC(i) end of character
     646             :             XTEXT_EOW(i) end of word
     647             :             XTEXT_EOS(i) end of sentence
     648             : 
     649             :             this three are with index and are created with the help of a i18n::XBreakIterator in
     650             :             ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
     651             :             data structure for holding those TEXT infos.
     652             :             Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
     653             :             primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
     654             :             that this creations do not need to be done for all paints all the time. This would be
     655             :             expensive since the BreakIterator and it's usage is expensive and for each paint also the
     656             :             whole character stops would need to be created.
     657             :             Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
     658             : 
     659             :             XTEXT_EOL() end of line
     660             :             XTEXT_EOP() end of paragraph
     661             : 
     662             :             First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
     663             :             i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
     664             :             namely:
     665             :             - TextHierarchyLinePrimitive2D: Encapsulates single line
     666             :             - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
     667             :             - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
     668             :             Those are now supported in hierarchy. This means the MetaFile renderer will support them
     669             :             by using them, reculrively using their content and adding MetaFile comments as needed.
     670             :             This also means that when another text layouter will be used it will be necessary to
     671             :             create/support the same HierarchyPrimitives to support users.
     672             :             To transport the information using this hierarchy is best suited to all future needs;
     673             :             the slideshow will be able to profit from it directly when using primitives; all other
     674             :             renderers not interested in the text structure will just ignore the encapsulations.
     675             : 
     676             :             XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
     677             :             Supported now by the TextHierarchyBlockPrimitive2D.
     678             : 
     679             :             EPSReplacementGraphic:
     680             :             Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
     681             :             hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
     682             :             used to export the original again (if exists).
     683             :             Not necessary to support with MetaFuleRenderer.
     684             : 
     685             :             XTEXT_SCROLLRECT, XTEXT_PAINTRECT
     686             :             Currently used to get extra MetaFile infos using GraphicExporter which again uses
     687             :             SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
     688             :             the rectangle data is added directly by the GraphicsExporter as comment. Does not need
     689             :             to be adapted at once.
     690             :             When adapting later, the only user - the diashow - should directly use the provided
     691             :             Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
     692             : 
     693             :             PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
     694             :             VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
     695             :             a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
     696             :             was explicitly created for the printer already again to some default maximum
     697             :             bitmap sizes.
     698             :             Nothing to do here for the primitive renderer.
     699             : 
     700             :             Support for vcl::PDFExtOutDevData:
     701             :             PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
     702             :             the OutDev. When set, some extra data is written there. Trying simple PDF export and
     703             :             watching if i get those infos.
     704             :             Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
     705             :             the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
     706             :             if i get a PDFExtOutDevData at the target output device.
     707             :             Indeed, i get one. Checking what all may be done when that extra-device-info is there.
     708             : 
     709             :             All in all i have to talk to SJ. I will need to emulate some of those actions, but
     710             :             i need to discuss which ones.
     711             :             In the future, all those infos would be taken from the primitive sequence anyways,
     712             :             thus these extensions would potentially be temporary, too.
     713             :             Discussed with SJ, added the necessary support and tested it. Details follow.
     714             : 
     715             :             - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
     716             :               Added in primitive MetaFile renderer.
     717             :               Checking URL: Indeed, current version exports it, but it is missing in primitive
     718             :               CWS version. Adding support.
     719             :               Okay, URLs work. Checked, Done.
     720             : 
     721             :             - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
     722             :               target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
     723             :               This may be added in primitive MetaFile renderer.
     724             :               Adding support...
     725             :               OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
     726             :               svxform. Have to talk to FS if this has to be like that. Especially since
     727             :               ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
     728             :               Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
     729             :               that stuff to somewhere else, maybe tools or svtools ?!? We will see...
     730             :               Moved to toolkit, so i have to link against it. I tried VCL first, but it did
     731             :               not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
     732             :               may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
     733             :               the lowest move,ment plave is toolkit.
     734             :               Checked form control export, it works well. Done.
     735             : 
     736             :             - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
     737             :               generated. I will need to check what happens here with primitives.
     738             :               To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
     739             :               Added support, but feature is broken in main version, so i cannot test at all.
     740             :               Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
     741             :               SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
     742             :               as intended, the original file is exported. Works, Done.
     743             : 
     744             : 
     745             : 
     746             : 
     747             :             To be done:
     748             : 
     749             :             - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
     750             : 
     751             : 
     752             : 
     753             :         ****************************************************************************************************/
     754             : 
     755          93 :         void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
     756             :         {
     757          93 :             switch(rCandidate.getPrimitive2DID())
     758             :             {
     759             :                 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
     760             :                 {
     761             :                     // directdraw of wrong spell primitive
     762             :                     // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
     763           0 :                     break;
     764             :                 }
     765             :                 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
     766             :                 {
     767           8 :                     const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
     768           8 :                     bool bUsingPDFExtOutDevData(false);
     769           8 :                     basegfx::B2DVector aTranslate, aScale;
     770             :                     static bool bSuppressPDFExtOutDevDataSupport(false);
     771             : 
     772           8 :                     if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
     773             :                     {
     774             :                         // emulate data handling from UnoControlPDFExportContact, original see
     775             :                         // svtools/source/graphic/grfmgr.cxx
     776           0 :                         const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
     777             : 
     778           0 :                         if(rGraphic.IsLink())
     779             :                         {
     780           0 :                             const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
     781             : 
     782           0 :                             if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
     783             :                             {
     784           0 :                                 const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
     785             :                                 double fRotate, fShearX;
     786           0 :                                 rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
     787             : 
     788           0 :                                 if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
     789             :                                 {
     790           0 :                                     bUsingPDFExtOutDevData = true;
     791           0 :                                     mpPDFExtOutDevData->BeginGroup();
     792             :                                 }
     793             :                             }
     794             :                         }
     795             :                     }
     796             : 
     797             :                     // process recursively and add MetaFile comment
     798           8 :                     process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
     799             : 
     800           8 :                     if(bUsingPDFExtOutDevData)
     801             :                     {
     802             :                         // emulate data handling from UnoControlPDFExportContact, original see
     803             :                         // svtools/source/graphic/grfmgr.cxx
     804             :                         const basegfx::B2DRange aCurrentRange(
     805             :                             aTranslate.getX(), aTranslate.getY(),
     806           0 :                             aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
     807             :                         const Rectangle aCurrentRect(
     808           0 :                             sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
     809           0 :                             sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
     810           0 :                         const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
     811           0 :                         Rectangle aCropRect;
     812             : 
     813           0 :                         if(rAttr.IsCropped())
     814             :                         {
     815             :                             // calculate scalings between real image size and logic object size. This
     816             :                             // is necessary since the crop values are relative to original bitmap size
     817           0 :                             double fFactorX(1.0);
     818           0 :                             double fFactorY(1.0);
     819             : 
     820             :                             {
     821           0 :                                 const MapMode aMapMode100thmm(MAP_100TH_MM);
     822           0 :                                 const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
     823           0 :                                     rGraphicPrimitive.getGraphicObject().GetPrefSize(),
     824           0 :                                     rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
     825           0 :                                 const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
     826           0 :                                 const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
     827             : 
     828           0 :                                 if(!basegfx::fTools::equalZero(fDivX))
     829             :                                 {
     830           0 :                                     fFactorX = aScale.getX() / fDivX;
     831             :                                 }
     832             : 
     833           0 :                                 if(!basegfx::fTools::equalZero(fDivY))
     834             :                                 {
     835           0 :                                     fFactorY = aScale.getY() / fDivY;
     836           0 :                                 }
     837             :                             }
     838             : 
     839             :                             // calculate crop range and rect
     840           0 :                             basegfx::B2DRange aCropRange;
     841           0 :                             aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
     842           0 :                             aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
     843             : 
     844             :                             aCropRect = Rectangle(
     845           0 :                                 sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
     846           0 :                                 sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
     847             :                         }
     848             : 
     849           0 :                         mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
     850           0 :                             rAttr.GetTransparency(),
     851             :                             aCurrentRect,
     852           0 :                             aCropRect);
     853             :                     }
     854             : 
     855           8 :                     break;
     856             :                 }
     857             :                 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
     858             :                 {
     859           0 :                     const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
     860           0 :                     const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
     861           0 :                     bool bIsPrintableControl(false);
     862             : 
     863             :                     // find out if control is printable
     864           0 :                     if(rXControl.is())
     865             :                     {
     866             :                         try
     867             :                         {
     868           0 :                             uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
     869           0 :                             uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
     870           0 :                                 ? xModelProperties->getPropertySetInfo()
     871           0 :                                 : uno::Reference< beans::XPropertySetInfo >());
     872           0 :                             const ::rtl::OUString sPrintablePropertyName("Printable");
     873             : 
     874           0 :                             if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
     875             :                             {
     876           0 :                                 OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
     877           0 :                             }
     878             :                         }
     879           0 :                         catch(const uno::Exception&)
     880             :                         {
     881             :                             OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
     882             :                         }
     883             :                     }
     884             : 
     885             :                     // PDF export and printing only for printable controls
     886           0 :                     if(bIsPrintableControl)
     887             :                     {
     888           0 :                         const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
     889           0 :                         bool bDoProcessRecursively(true);
     890             : 
     891           0 :                         if(bPDFExport)
     892             :                         {
     893             :                             // PDF export. Emulate data handling from UnoControlPDFExportContact
     894             :                             // I have now moved describePDFControl to toolkit, thus i can implement the PDF
     895             :                             // form control support now as follows
     896           0 :                             ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
     897           0 :                             ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData );
     898             : 
     899           0 :                             if(pPDFControl.get())
     900             :                             {
     901             :                                 // still need to fill in the location (is a class Rectangle)
     902           0 :                                 const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
     903             :                                 const Rectangle aRectLogic(
     904           0 :                                     (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
     905           0 :                                     (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
     906           0 :                                 pPDFControl->Location = aRectLogic;
     907             : 
     908           0 :                                 Size aFontSize(pPDFControl->TextFont.GetSize());
     909           0 :                                 aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
     910           0 :                                 pPDFControl->TextFont.SetSize(aFontSize);
     911             : 
     912           0 :                                 mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
     913           0 :                                 mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
     914           0 :                                 mpPDFExtOutDevData->EndStructureElement();
     915             : 
     916             :                                 // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
     917             :                                 // do not process recursively
     918           0 :                                 bDoProcessRecursively = false;
     919             :                             }
     920             :                             else
     921             :                             {
     922             :                                 // PDF export did not work, try simple output.
     923             :                                 // Fallback to printer output by not setting bDoProcessRecursively
     924             :                                 // to false.
     925           0 :                             }
     926             :                         }
     927             : 
     928             :                         // #i93169# used flag the wrong way; true means that nothing was done yet
     929           0 :                         if(bDoProcessRecursively)
     930             :                         {
     931             :                             // printer output
     932             :                             try
     933             :                             {
     934             :                                 // remember old graphics and create new
     935           0 :                                 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
     936           0 :                                 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
     937           0 :                                 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
     938             : 
     939           0 :                                 if(xNewGraphics.is())
     940             :                                 {
     941             :                                     // link graphics and view
     942           0 :                                     xControlView->setGraphics(xNewGraphics);
     943             : 
     944             :                                     // get position
     945           0 :                                     const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
     946           0 :                                     const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
     947             : 
     948             :                                     // draw it
     949           0 :                                     xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
     950           0 :                                     bDoProcessRecursively = false;
     951             : 
     952             :                                     // restore original graphics
     953           0 :                                     xControlView->setGraphics(xOriginalGraphics);
     954           0 :                                 }
     955             :                             }
     956           0 :                             catch( const uno::Exception& )
     957             :                             {
     958             :                                 OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
     959             :                             }
     960             :                         }
     961             : 
     962             :                         // process recursively if not done yet to export as decomposition (bitmap)
     963           0 :                         if(bDoProcessRecursively)
     964             :                         {
     965           0 :                             process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
     966             :                         }
     967             :                     }
     968             : 
     969             :                     break;
     970             :                 }
     971             :                 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
     972             :                 {
     973             :                     // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
     974             :                     // thus do the MetafileAction embedding stuff but just handle recursively.
     975           0 :                     const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
     976           0 :                     const rtl::OString aCommentStringCommon(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN"));
     977           0 :                     const rtl::OString aCommentStringPage(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN;PageField"));
     978           0 :                     const rtl::OString aCommentStringEnd(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END"));
     979             : 
     980           0 :                     switch(rFieldPrimitive.getType())
     981             :                     {
     982             :                         default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
     983             :                         {
     984           0 :                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
     985           0 :                             break;
     986             :                         }
     987             :                         case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
     988             :                         {
     989           0 :                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
     990           0 :                             break;
     991             :                         }
     992             :                         case drawinglayer::primitive2d::FIELD_TYPE_URL :
     993             :                         {
     994           0 :                             const rtl::OUString& rURL = rFieldPrimitive.getString();
     995           0 :                             const String aOldString(rURL);
     996           0 :                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
     997           0 :                             break;
     998             :                         }
     999             :                     }
    1000             : 
    1001             :                     // process recursively
    1002           0 :                     const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
    1003           0 :                     process(rContent);
    1004             : 
    1005             :                     // for the end comment the type is not relevant yet, they are all the same. Just add.
    1006           0 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
    1007             : 
    1008           0 :                     if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
    1009             :                     {
    1010             :                         // emulate data handling from ImpEditEngine::Paint
    1011           0 :                         const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
    1012             :                         const Rectangle aRectLogic(
    1013           0 :                             (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
    1014           0 :                             (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
    1015           0 :                         vcl::PDFExtOutDevBookmarkEntry aBookmark;
    1016           0 :                         aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
    1017           0 :                         aBookmark.aBookmark = rFieldPrimitive.getString();
    1018           0 :                         std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
    1019           0 :                         rBookmarks.push_back( aBookmark );
    1020             :                     }
    1021             : 
    1022           0 :                     break;
    1023             :                 }
    1024             :                 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
    1025             :                 {
    1026           3 :                     const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
    1027           3 :                     const rtl::OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOL"));
    1028             : 
    1029             :                     // process recursively and add MetaFile comment
    1030           3 :                     process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
    1031           3 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
    1032             : 
    1033           3 :                     break;
    1034             :                 }
    1035             :                 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
    1036             :                 {
    1037             :                     // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
    1038             :                     // "XTEXT_EOC" is used, use here, too.
    1039           0 :                     const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
    1040           0 :                     const rtl::OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOC"));
    1041             : 
    1042             :                     // process recursively and add MetaFile comment
    1043           0 :                     process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
    1044           0 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
    1045             : 
    1046           0 :                     break;
    1047             :                 }
    1048             :                 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
    1049             :                 {
    1050           3 :                     const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
    1051           3 :                     const rtl::OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOP"));
    1052             : 
    1053           3 :                     if(mpPDFExtOutDevData)
    1054             :                     {
    1055             :                         // emulate data handling from ImpEditEngine::Paint
    1056           0 :                         mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
    1057             :                     }
    1058             : 
    1059             :                     // process recursively and add MetaFile comment
    1060           3 :                     process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
    1061           3 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
    1062             : 
    1063           3 :                     if(mpPDFExtOutDevData)
    1064             :                     {
    1065             :                         // emulate data handling from ImpEditEngine::Paint
    1066           0 :                         mpPDFExtOutDevData->EndStructureElement();
    1067             :                     }
    1068             : 
    1069           3 :                     break;
    1070             :                 }
    1071             :                 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
    1072             :                 {
    1073           3 :                     const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
    1074           3 :                     const rtl::OString aCommentStringA(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_BEGIN"));
    1075           3 :                     const rtl::OString aCommentStringB(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_END"));
    1076             : 
    1077             :                     // add MetaFile comment, process recursively and add MetaFile comment
    1078           3 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
    1079           3 :                     process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
    1080           3 :                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
    1081             : 
    1082           3 :                     break;
    1083             :                 }
    1084             :                 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
    1085             :                 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
    1086             :                 {
    1087             :                     // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
    1088           5 :                     const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
    1089             :                     // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
    1090             : 
    1091             :                     // Adapt evtl. used special DrawMode
    1092           5 :                     const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
    1093           5 :                     adaptTextToFillDrawMode();
    1094             : 
    1095             :                     // directdraw of text simple portion; use default processing
    1096           5 :                     RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
    1097             : 
    1098             :                     // restore DrawMode
    1099           5 :                     mpOutputDevice->SetDrawMode(nOriginalDrawMode);
    1100             : 
    1101             :                     // #i101169# if(pTextDecoratedCandidate)
    1102             :                     {
    1103             :                         // support for TEXT_ MetaFile actions only for decorated texts
    1104           5 :                         if(!mxBreakIterator.is())
    1105             :                         {
    1106           1 :                             uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
    1107           1 :                             mxBreakIterator = i18n::BreakIterator::create(xContext);
    1108             :                         }
    1109             : 
    1110           5 :                         const rtl::OUString& rTxt = rTextCandidate.getText();
    1111           5 :                         const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
    1112             : 
    1113           5 :                         if(nTextLength)
    1114             :                         {
    1115           5 :                             const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
    1116           5 :                             const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
    1117             : 
    1118             :                             sal_Int32 nDone;
    1119           5 :                             sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
    1120           5 :                             ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
    1121           5 :                             sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
    1122           5 :                             const rtl::OString aCommentStringA(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOC"));
    1123           5 :                             const rtl::OString aCommentStringB(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOW"));
    1124           5 :                             const rtl::OString aCommentStringC(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOS"));
    1125             : 
    1126          50 :                             for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
    1127             :                             {
    1128             :                                 // create the entries for the respective break positions
    1129          45 :                                 if(i == nNextCellBreak)
    1130             :                                 {
    1131          45 :                                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
    1132          45 :                                     nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
    1133             :                                 }
    1134          45 :                                 if(i == nNextWordBoundary.endPos)
    1135             :                                 {
    1136           0 :                                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
    1137           0 :                                     nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
    1138             :                                 }
    1139          45 :                                 if(i == nNextSentenceBreak)
    1140             :                                 {
    1141           0 :                                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
    1142           0 :                                     nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
    1143             :                                 }
    1144           5 :                             }
    1145           5 :                         }
    1146             :                     }
    1147             : 
    1148           5 :                     break;
    1149             :                 }
    1150             :                 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
    1151             :                 {
    1152           1 :                     const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
    1153           1 :                     const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
    1154             : 
    1155           1 :                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
    1156             :                     {
    1157             :                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1158             :                         // per polygon. If there are more, split the polygon in half and call recursively
    1159           0 :                         basegfx::B2DPolygon aLeft, aRight;
    1160           0 :                         splitLinePolygon(rBasePolygon, aLeft, aRight);
    1161           0 :                         const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
    1162           0 :                         const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
    1163             : 
    1164           0 :                         processBasePrimitive2D(aPLeft);
    1165           0 :                         processBasePrimitive2D(aPRight);
    1166             :                     }
    1167             :                     else
    1168             :                     {
    1169             :                         // direct draw of hairline; use default processing
    1170             :                         // support SvtGraphicStroke MetaCommentAction
    1171           1 :                         const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
    1172             :                         SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
    1173           1 :                             rHairlinePrimitive.getB2DPolygon(),
    1174             :                             &aLineColor,
    1175           1 :                             0, 0, 0, 0);
    1176             : 
    1177           1 :                         impStartSvtGraphicStroke(pSvtGraphicStroke);
    1178           1 :                         RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
    1179           1 :                         impEndSvtGraphicStroke(pSvtGraphicStroke);
    1180             :                     }
    1181           1 :                     break;
    1182             :                 }
    1183             :                 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
    1184             :                 {
    1185           6 :                     const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
    1186           6 :                     const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
    1187             : 
    1188           6 :                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
    1189             :                     {
    1190             :                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1191             :                         // per polygon. If there are more, split the polygon in half and call recursively
    1192           0 :                         basegfx::B2DPolygon aLeft, aRight;
    1193           0 :                         splitLinePolygon(rBasePolygon, aLeft, aRight);
    1194             :                         const primitive2d::PolygonStrokePrimitive2D aPLeft(
    1195           0 :                             aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
    1196             :                         const primitive2d::PolygonStrokePrimitive2D aPRight(
    1197           0 :                             aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
    1198             : 
    1199           0 :                         processBasePrimitive2D(aPLeft);
    1200           0 :                         processBasePrimitive2D(aPRight);
    1201             :                     }
    1202             :                     else
    1203             :                     {
    1204             :                         // support SvtGraphicStroke MetaCommentAction
    1205             :                         SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
    1206             :                             rBasePolygon, 0,
    1207           6 :                             &rStrokePrimitive.getLineAttribute(),
    1208           6 :                             &rStrokePrimitive.getStrokeAttribute(),
    1209           6 :                             0, 0);
    1210             : 
    1211           6 :                         impStartSvtGraphicStroke(pSvtGraphicStroke);
    1212           6 :                         const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
    1213             : 
    1214             :                         // create MetaPolyLineActions, but without LINE_DASH
    1215           6 :                         if(basegfx::fTools::more(rLine.getWidth(), 0.0))
    1216             :                         {
    1217           5 :                             const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
    1218           5 :                             basegfx::B2DPolyPolygon aHairLinePolyPolygon;
    1219             : 
    1220           5 :                             if(0.0 == rStroke.getFullDotDashLen())
    1221             :                             {
    1222           5 :                                 aHairLinePolyPolygon.append(rBasePolygon);
    1223             :                             }
    1224             :                             else
    1225             :                             {
    1226             :                                 basegfx::tools::applyLineDashing(
    1227           0 :                                     rBasePolygon, rStroke.getDotDashArray(),
    1228           0 :                                     &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
    1229             :                             }
    1230             : 
    1231           5 :                             const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
    1232           5 :                             mpOutputDevice->SetLineColor(Color(aHairlineColor));
    1233           5 :                             mpOutputDevice->SetFillColor();
    1234           5 :                             aHairLinePolyPolygon.transform(maCurrentTransformation);
    1235             : 
    1236             :                             // #i113922# LineWidth needs to be transformed, too
    1237           5 :                             const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0));
    1238           5 :                             const double fDiscreteLineWidth(aDiscreteUnit.getLength());
    1239             : 
    1240           5 :                             LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth));
    1241           5 :                             aLineInfo.SetLineJoin(rLine.getLineJoin());
    1242           5 :                             aLineInfo.SetLineCap(rLine.getLineCap());
    1243             : 
    1244          10 :                             for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
    1245             :                             {
    1246           5 :                                 const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
    1247             : 
    1248           5 :                                 if(aCandidate.count() > 1)
    1249             :                                 {
    1250           5 :                                     const Polygon aToolsPolygon(aCandidate);
    1251             : 
    1252           5 :                                     mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
    1253             :                                 }
    1254          10 :                             }
    1255             :                         }
    1256             :                         else
    1257             :                         {
    1258           1 :                             process(rCandidate.get2DDecomposition(getViewInformation2D()));
    1259             :                         }
    1260             : 
    1261           6 :                         impEndSvtGraphicStroke(pSvtGraphicStroke);
    1262             :                     }
    1263             : 
    1264           6 :                     break;
    1265             :                 }
    1266             :                 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
    1267             :                 {
    1268           1 :                     const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
    1269           1 :                     const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
    1270             : 
    1271           1 :                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
    1272             :                     {
    1273             :                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1274             :                         // per polygon. If there are more, split the polygon in half and call recursively
    1275           0 :                         basegfx::B2DPolygon aLeft, aRight;
    1276           0 :                         splitLinePolygon(rBasePolygon, aLeft, aRight);
    1277           0 :                         const attribute::LineStartEndAttribute aEmpty;
    1278             :                         const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
    1279             :                             aLeft,
    1280           0 :                             rStrokeArrowPrimitive.getLineAttribute(),
    1281           0 :                             rStrokeArrowPrimitive.getStrokeAttribute(),
    1282           0 :                             rStrokeArrowPrimitive.getStart(),
    1283           0 :                             aEmpty);
    1284             :                         const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
    1285             :                             aRight,
    1286           0 :                             rStrokeArrowPrimitive.getLineAttribute(),
    1287           0 :                             rStrokeArrowPrimitive.getStrokeAttribute(),
    1288             :                             aEmpty,
    1289           0 :                             rStrokeArrowPrimitive.getEnd());
    1290             : 
    1291           0 :                         processBasePrimitive2D(aPLeft);
    1292           0 :                         processBasePrimitive2D(aPRight);
    1293             :                     }
    1294             :                     else
    1295             :                     {
    1296             :                         // support SvtGraphicStroke MetaCommentAction
    1297             :                         SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
    1298             :                             rBasePolygon, 0,
    1299           1 :                             &rStrokeArrowPrimitive.getLineAttribute(),
    1300           1 :                             &rStrokeArrowPrimitive.getStrokeAttribute(),
    1301           1 :                             &rStrokeArrowPrimitive.getStart(),
    1302           2 :                             &rStrokeArrowPrimitive.getEnd());
    1303             : 
    1304           1 :                         impStartSvtGraphicStroke(pSvtGraphicStroke);
    1305           1 :                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
    1306           1 :                         impEndSvtGraphicStroke(pSvtGraphicStroke);
    1307             :                     }
    1308             : 
    1309           1 :                     break;
    1310             :                 }
    1311             :                 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
    1312             :                 {
    1313             :                     // direct draw of transformed BitmapEx primitive; use default processing
    1314           8 :                     RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
    1315           8 :                     break;
    1316             :                 }
    1317             :                 case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
    1318             :                 {
    1319             :                     // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
    1320           0 :                     const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate);
    1321           0 :                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
    1322             : 
    1323           0 :                     if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
    1324             :                     {
    1325             :                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1326             :                         // per polygon. If there are more use the splitted polygon and call recursively
    1327             :                         const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted(
    1328             :                             aLocalPolyPolygon,
    1329           0 :                             rBitmapCandidate.getFillBitmap());
    1330             : 
    1331           0 :                         processBasePrimitive2D(aSplitted);
    1332             :                     }
    1333             :                     else
    1334             :                     {
    1335           0 :                         SvtGraphicFill* pSvtGraphicFill = 0;
    1336             : 
    1337           0 :                         if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
    1338             :                         {
    1339           0 :                             aLocalPolyPolygon.transform(maCurrentTransformation);
    1340             :                             // calculate transformation. Get real object size, all values in FillBitmapAttribute
    1341             :                             // are relative to the unified object
    1342           0 :                             const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap();
    1343           0 :                             const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon));
    1344           0 :                             const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange());
    1345             : 
    1346             :                             // get absolute values
    1347           0 :                             const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize);
    1348           0 :                             const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize);
    1349             : 
    1350             :                             // the scaling needs scale from pixel to logic coordinate system
    1351           0 :                             const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
    1352           0 :                             Size aBmpSizePixel(rBitmapEx.GetSizePixel());
    1353             : 
    1354           0 :                             if(!aBmpSizePixel.Width())
    1355             :                             {
    1356           0 :                                 aBmpSizePixel.Width() = 1;
    1357             :                             }
    1358             : 
    1359           0 :                             if(!aBmpSizePixel.Height())
    1360             :                             {
    1361           0 :                                 aBmpSizePixel.Height() = 1;
    1362             :                             }
    1363             : 
    1364             :                             // setup transformation like in impgrfll
    1365           0 :                             SvtGraphicFill::Transform aTransform;
    1366             : 
    1367             :                             // scale values are divided by bitmap pixel sizes
    1368           0 :                             aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width();
    1369           0 :                             aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height();
    1370             : 
    1371             :                             // translates are absolute
    1372           0 :                             aTransform.matrix[2] = aFillBitmapTopLeft.getX();
    1373           0 :                             aTransform.matrix[5] = aFillBitmapTopLeft.getY();
    1374             : 
    1375             :                             // setup fill graphic like in impgrfll
    1376           0 :                             Graphic aFillGraphic = Graphic(rBitmapEx);
    1377           0 :                             aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL));
    1378           0 :                             aFillGraphic.SetPrefSize(aBmpSizePixel);
    1379             : 
    1380             :                             pSvtGraphicFill = new SvtGraphicFill(
    1381             :                                 getFillPolyPolygon(aLocalPolyPolygon),
    1382             :                                 Color(),
    1383             :                                 0.0,
    1384             :                                 SvtGraphicFill::fillEvenOdd,
    1385             :                                 SvtGraphicFill::fillTexture,
    1386             :                                 aTransform,
    1387           0 :                                 rFillBitmapAttribute.getTiling(),
    1388             :                                 SvtGraphicFill::hatchSingle,
    1389             :                                 Color(),
    1390             :                                 SvtGraphicFill::gradientLinear,
    1391             :                                 Color(),
    1392             :                                 Color(),
    1393             :                                 0,
    1394           0 :                                 aFillGraphic);
    1395             :                         }
    1396             : 
    1397             :                         // Do use decomposition; encapsulate with SvtGraphicFill
    1398           0 :                         impStartSvtGraphicFill(pSvtGraphicFill);
    1399           0 :                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
    1400           0 :                         impEndSvtGraphicFill(pSvtGraphicFill);
    1401             :                     }
    1402             : 
    1403           0 :                     break;
    1404             :                 }
    1405             :                 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
    1406             :                 {
    1407             :                     // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
    1408           0 :                     const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
    1409           0 :                     const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
    1410           0 :                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
    1411             : 
    1412             :                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1413             :                     // per polygon. Split polygon until there are less than that
    1414           0 :                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
    1415             :                         ;
    1416             : 
    1417           0 :                     if(rFillHatchAttribute.isFillBackground())
    1418             :                     {
    1419             :                         // with fixing #i111954# (see below) the possible background
    1420             :                         // fill of a hatched object was lost.Generate a background fill
    1421             :                         // primitive and render it
    1422             :                         const primitive2d::Primitive2DReference xBackground(
    1423             :                             new primitive2d::PolyPolygonColorPrimitive2D(
    1424             :                                 aLocalPolyPolygon,
    1425           0 :                                 rHatchCandidate.getBackgroundColor()));
    1426             : 
    1427           0 :                         process(primitive2d::Primitive2DSequence(&xBackground, 1));
    1428             :                     }
    1429             : 
    1430           0 :                     SvtGraphicFill* pSvtGraphicFill = 0;
    1431           0 :                     aLocalPolyPolygon.transform(maCurrentTransformation);
    1432             : 
    1433           0 :                     if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
    1434             :                     {
    1435             :                         // re-create a VCL hatch as base data
    1436           0 :                         SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
    1437             : 
    1438           0 :                         switch(rFillHatchAttribute.getStyle())
    1439             :                         {
    1440             :                             default: // attribute::HATCHSTYLE_SINGLE :
    1441             :                             {
    1442           0 :                                 eHatch = SvtGraphicFill::hatchSingle;
    1443           0 :                                 break;
    1444             :                             }
    1445             :                             case attribute::HATCHSTYLE_DOUBLE :
    1446             :                             {
    1447           0 :                                 eHatch = SvtGraphicFill::hatchDouble;
    1448           0 :                                 break;
    1449             :                             }
    1450             :                             case attribute::HATCHSTYLE_TRIPLE :
    1451             :                             {
    1452           0 :                                 eHatch = SvtGraphicFill::hatchTriple;
    1453           0 :                                 break;
    1454             :                             }
    1455             :                         }
    1456             : 
    1457           0 :                         SvtGraphicFill::Transform aTransform;
    1458             : 
    1459             :                         // scale
    1460           0 :                         aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
    1461           0 :                         aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
    1462             : 
    1463             :                         // rotate (was never correct in impgrfll anyways, use correct angle now)
    1464           0 :                         aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
    1465           0 :                         aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
    1466           0 :                         aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
    1467           0 :                         aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
    1468             : 
    1469             :                         pSvtGraphicFill = new SvtGraphicFill(
    1470             :                             getFillPolyPolygon(aLocalPolyPolygon),
    1471             :                             Color(),
    1472             :                             0.0,
    1473             :                             SvtGraphicFill::fillEvenOdd,
    1474             :                             SvtGraphicFill::fillHatch,
    1475             :                             aTransform,
    1476             :                             false,
    1477             :                             eHatch,
    1478           0 :                             Color(rFillHatchAttribute.getColor()),
    1479             :                             SvtGraphicFill::gradientLinear,
    1480             :                             Color(),
    1481             :                             Color(),
    1482             :                             0,
    1483           0 :                             Graphic());
    1484             :                     }
    1485             : 
    1486             :                     // Do use decomposition; encapsulate with SvtGraphicFill
    1487           0 :                     impStartSvtGraphicFill(pSvtGraphicFill);
    1488             : 
    1489             :                     // #i111954# do NOT use decomposition, but use direct VCL-command
    1490             :                     // process(rCandidate.get2DDecomposition(getViewInformation2D()));
    1491           0 :                     const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon);
    1492             :                     const HatchStyle aHatchStyle(
    1493           0 :                         attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
    1494           0 :                         attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
    1495           0 :                         HATCH_TRIPLE);
    1496             : 
    1497             :                     mpOutputDevice->DrawHatch(aToolsPolyPolygon,
    1498             :                         Hatch(aHatchStyle,
    1499           0 :                             Color(rFillHatchAttribute.getColor()),
    1500             :                             basegfx::fround(rFillHatchAttribute.getDistance()),
    1501           0 :                             basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
    1502             : 
    1503           0 :                     impEndSvtGraphicFill(pSvtGraphicFill);
    1504             : 
    1505           0 :                     break;
    1506             :                 }
    1507             :                 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
    1508             :                 {
    1509           0 :                     const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
    1510           0 :                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
    1511             : 
    1512             :                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1513             :                     // per polygon. Split polygon until there are less than that
    1514           0 :                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
    1515             :                         ;
    1516             : 
    1517             :                     // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
    1518             :                     // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
    1519             :                     // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
    1520           0 :                     Gradient aVCLGradient;
    1521           0 :                     impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
    1522           0 :                     aLocalPolyPolygon.transform(maCurrentTransformation);
    1523             : 
    1524             :                     // #i82145# ATM VCL printing of gradients using curved shapes does not work,
    1525             :                     // i submitted the bug with the given ID to THB. When that task is fixed it is
    1526             :                     // necessary to again remove this subdivision since it decreases possible
    1527             :                     // printing quality (not even resolution-dependent for now). THB will tell
    1528             :                     // me when that task is fixed in the master
    1529             :                     const PolyPolygon aToolsPolyPolygon(
    1530             :                         getFillPolyPolygon(
    1531           0 :                             basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
    1532             : 
    1533             :                     // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
    1534           0 :                     SvtGraphicFill* pSvtGraphicFill = 0;
    1535             : 
    1536           0 :                     if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
    1537             :                     {
    1538             :                         // setup gradient stuff like in like in impgrfll
    1539           0 :                         SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
    1540             : 
    1541           0 :                         switch(aVCLGradient.GetStyle())
    1542             :                         {
    1543             :                             default : // GradientStyle_LINEAR:
    1544             :                             case GradientStyle_AXIAL:
    1545           0 :                                 eGrad = SvtGraphicFill::gradientLinear;
    1546           0 :                                 break;
    1547             :                             case GradientStyle_RADIAL:
    1548             :                             case GradientStyle_ELLIPTICAL:
    1549           0 :                                 eGrad = SvtGraphicFill::gradientRadial;
    1550           0 :                                 break;
    1551             :                             case GradientStyle_SQUARE:
    1552             :                             case GradientStyle_RECT:
    1553           0 :                                 eGrad = SvtGraphicFill::gradientRectangular;
    1554           0 :                                 break;
    1555             :                         }
    1556             : 
    1557             :                         pSvtGraphicFill = new SvtGraphicFill(
    1558             :                             aToolsPolyPolygon,
    1559             :                             Color(),
    1560             :                             0.0,
    1561             :                             SvtGraphicFill::fillEvenOdd,
    1562             :                             SvtGraphicFill::fillGradient,
    1563             :                             SvtGraphicFill::Transform(),
    1564             :                             false,
    1565             :                             SvtGraphicFill::hatchSingle,
    1566             :                             Color(),
    1567             :                             eGrad,
    1568           0 :                             aVCLGradient.GetStartColor(),
    1569           0 :                             aVCLGradient.GetEndColor(),
    1570           0 :                             aVCLGradient.GetSteps(),
    1571           0 :                             Graphic());
    1572             :                     }
    1573             : 
    1574             :                     // call VCL directly; encapsulate with SvtGraphicFill
    1575           0 :                     impStartSvtGraphicFill(pSvtGraphicFill);
    1576           0 :                     mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
    1577           0 :                     impEndSvtGraphicFill(pSvtGraphicFill);
    1578             : 
    1579             :                     // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above
    1580             :                     // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
    1581             : 
    1582           0 :                     break;
    1583             :                 }
    1584             :                 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
    1585             :                 {
    1586          19 :                     const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
    1587          19 :                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
    1588             : 
    1589             :                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1590             :                     // per polygon. Split polygon until there are less than that
    1591          19 :                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
    1592             :                         ;
    1593             : 
    1594          19 :                     const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
    1595          19 :                     aLocalPolyPolygon.transform(maCurrentTransformation);
    1596             : 
    1597             :                     // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
    1598          19 :                     SvtGraphicFill* pSvtGraphicFill = 0;
    1599             : 
    1600          19 :                     if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
    1601             :                     {
    1602             :                         // setup simple color fill stuff like in impgrfll
    1603             :                         pSvtGraphicFill = new SvtGraphicFill(
    1604             :                             getFillPolyPolygon(aLocalPolyPolygon),
    1605             :                             Color(aPolygonColor),
    1606             :                             0.0,
    1607             :                             SvtGraphicFill::fillEvenOdd,
    1608             :                             SvtGraphicFill::fillSolid,
    1609             :                             SvtGraphicFill::Transform(),
    1610             :                             false,
    1611             :                             SvtGraphicFill::hatchSingle,
    1612             :                             Color(),
    1613             :                             SvtGraphicFill::gradientLinear,
    1614             :                             Color(),
    1615             :                             Color(),
    1616             :                             0,
    1617          19 :                             Graphic());
    1618             :                     }
    1619             : 
    1620             :                     // set line and fill color
    1621          19 :                     mpOutputDevice->SetFillColor(Color(aPolygonColor));
    1622          19 :                     mpOutputDevice->SetLineColor();
    1623             : 
    1624             :                     // call VCL directly; encapsulate with SvtGraphicFill
    1625          19 :                     impStartSvtGraphicFill(pSvtGraphicFill);
    1626          19 :                     mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
    1627          19 :                     impEndSvtGraphicFill(pSvtGraphicFill);
    1628             : 
    1629          19 :                     break;
    1630             :                 }
    1631             :                 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
    1632             :                 {
    1633             :                     static bool bUseMetaFilePrimitiveDecomposition(true);
    1634           1 :                     const primitive2d::MetafilePrimitive2D& aMetafile = static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate);
    1635             : 
    1636           1 :                     if(bUseMetaFilePrimitiveDecomposition && !aMetafile.getMetaFile().GetUseCanvas())
    1637             :                     {
    1638             :                         // use new Metafile decomposition
    1639           1 :                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
    1640             :                     }
    1641             :                     else
    1642             :                     {
    1643             :                         // direct draw of MetaFile, use default pocessing
    1644           0 :                         RenderMetafilePrimitive2D(aMetafile);
    1645             :                     }
    1646             : 
    1647           1 :                     break;
    1648             :                 }
    1649             :                 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
    1650             :                 {
    1651             :                     // mask group. Special handling for MetaFiles.
    1652           2 :                     const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
    1653             : 
    1654           2 :                     if(rMaskCandidate.getChildren().hasElements())
    1655             :                     {
    1656           2 :                         basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
    1657             : 
    1658           2 :                         if(aMask.count())
    1659             :                         {
    1660             :                             // prepare new mask polygon and rescue current one
    1661           2 :                             aMask.transform(maCurrentTransformation);
    1662           2 :                             const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
    1663             : 
    1664           2 :                             if(maClipPolyPolygon.count())
    1665             :                             {
    1666             :                                 // there is already a clip polygon set; build clipped union of
    1667             :                                 // current mask polygon and new one
    1668             :                                 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
    1669             :                                     aMask,
    1670             :                                     maClipPolyPolygon,
    1671             :                                     true, // #i106516# we want the inside of aMask, not the outside
    1672           0 :                                     false);
    1673             :                             }
    1674             :                             else
    1675             :                             {
    1676             :                                 // use mask directly
    1677           2 :                                 maClipPolyPolygon = aMask;
    1678             :                             }
    1679             : 
    1680           2 :                             if(maClipPolyPolygon.count())
    1681             :                             {
    1682             :                                 // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
    1683             :                                 // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
    1684             :                                 // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
    1685           2 :                                 mpOutputDevice->Push(PUSH_CLIPREGION);
    1686             :                                 //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
    1687             :                                 //mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
    1688           2 :                                 mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon));
    1689             :                             }
    1690             : 
    1691             :                             // recursively paint content
    1692           2 :                             process(rMaskCandidate.getChildren());
    1693             : 
    1694           2 :                             if(maClipPolyPolygon.count())
    1695             :                             {
    1696             :                                 // restore VCL clip region
    1697           2 :                                 mpOutputDevice->Pop();
    1698             :                             }
    1699             : 
    1700             :                             // restore to rescued clip polygon
    1701           2 :                             maClipPolyPolygon = aLastClipPolyPolygon;
    1702             :                         }
    1703             :                         else
    1704             :                         {
    1705             :                             // no mask, no clipping. recursively paint content
    1706           0 :                             process(rMaskCandidate.getChildren());
    1707           2 :                         }
    1708             :                     }
    1709             : 
    1710           2 :                     break;
    1711             :                 }
    1712             :                 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
    1713             :                 {
    1714             :                     // modified color group. Force output to unified color. Use default pocessing.
    1715           0 :                     RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
    1716           0 :                     break;
    1717             :                 }
    1718             :                 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
    1719             :                 {
    1720             :                     // for metafile: Need to examine what the pure vcl version is doing here actually
    1721             :                     // - uses DrawTransparent with metafile for content and a gradient
    1722             :                     // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
    1723             :                     //   checking the content for single PolyPolygonColorPrimitive2D
    1724           0 :                     const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
    1725           0 :                     const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
    1726             : 
    1727           0 :                     if(rContent.hasElements())
    1728             :                     {
    1729           0 :                         if(0.0 == rUniTransparenceCandidate.getTransparence())
    1730             :                         {
    1731             :                             // not transparent at all, use content
    1732           0 :                             process(rUniTransparenceCandidate.getChildren());
    1733             :                         }
    1734           0 :                         else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
    1735             :                         {
    1736             :                             // try to identify a single PolyPolygonColorPrimitive2D in the
    1737             :                             // content part of the transparence primitive
    1738           0 :                             const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
    1739             :                             static bool bForceToMetafile(false);
    1740             : 
    1741           0 :                             if(!bForceToMetafile && 1 == rContent.getLength())
    1742             :                             {
    1743           0 :                                 const primitive2d::Primitive2DReference xReference(rContent[0]);
    1744           0 :                                 pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
    1745             :                             }
    1746             : 
    1747             :                             // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
    1748             :                             // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D.
    1749             :                             // Check also for correct ID to exclude derived implementations
    1750           0 :                             if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
    1751             :                             {
    1752             :                                 // single transparent PolyPolygon identified, use directly
    1753           0 :                                 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
    1754           0 :                                 basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
    1755             : 
    1756             :                                 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
    1757             :                                 // per polygon. Split polygon until there are less than that
    1758           0 :                                 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
    1759             :                                     ;
    1760             : 
    1761             :                                 // now transform
    1762           0 :                                 aLocalPolyPolygon.transform(maCurrentTransformation);
    1763             : 
    1764             :                                 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
    1765           0 :                                 SvtGraphicFill* pSvtGraphicFill = 0;
    1766             : 
    1767           0 :                                 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
    1768             :                                 {
    1769             :                                     // setup simple color with transparence fill stuff like in impgrfll
    1770             :                                     pSvtGraphicFill = new SvtGraphicFill(
    1771             :                                         getFillPolyPolygon(aLocalPolyPolygon),
    1772             :                                         Color(aPolygonColor),
    1773             :                                         rUniTransparenceCandidate.getTransparence(),
    1774             :                                         SvtGraphicFill::fillEvenOdd,
    1775             :                                         SvtGraphicFill::fillSolid,
    1776             :                                         SvtGraphicFill::Transform(),
    1777             :                                         false,
    1778             :                                         SvtGraphicFill::hatchSingle,
    1779             :                                         Color(),
    1780             :                                         SvtGraphicFill::gradientLinear,
    1781             :                                         Color(),
    1782             :                                         Color(),
    1783             :                                         0,
    1784           0 :                                         Graphic());
    1785             :                                 }
    1786             : 
    1787             :                                 // set line and fill color
    1788           0 :                                 const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
    1789           0 :                                 mpOutputDevice->SetFillColor(Color(aPolygonColor));
    1790           0 :                                 mpOutputDevice->SetLineColor();
    1791             : 
    1792             :                                 // call VCL directly; encapsulate with SvtGraphicFill
    1793           0 :                                 impStartSvtGraphicFill(pSvtGraphicFill);
    1794             :                                 mpOutputDevice->DrawTransparent(
    1795             :                                     PolyPolygon(aLocalPolyPolygon),
    1796           0 :                                     nTransPercentVcl);
    1797           0 :                                 impEndSvtGraphicFill(pSvtGraphicFill);
    1798             :                             }
    1799             :                             else
    1800             :                             {
    1801             :                                 // svae old mfCurrentUnifiedTransparence and set new one
    1802             :                                 // so that contained SvtGraphicStroke may use the current one
    1803           0 :                                 const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
    1804             :                                 // #i105377# paint the content metafile opaque as the transparency gets
    1805             :                                 // split of into the gradient below
    1806             :                                 // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
    1807           0 :                                 mfCurrentUnifiedTransparence = 0;
    1808             : 
    1809             :                                 // various content, create content-metafile
    1810           0 :                                 GDIMetaFile aContentMetafile;
    1811           0 :                                 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
    1812             : 
    1813             :                                 // restore mfCurrentUnifiedTransparence; it may have been used
    1814             :                                 // while processing the sub-content in impDumpToMetaFile
    1815           0 :                                 mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
    1816             : 
    1817             :                                 // create uniform VCL gradient for uniform transparency
    1818           0 :                                 Gradient aVCLGradient;
    1819           0 :                                 const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
    1820           0 :                                 const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
    1821             : 
    1822           0 :                                 aVCLGradient.SetStyle(GradientStyle_LINEAR);
    1823           0 :                                 aVCLGradient.SetStartColor(aTransColor);
    1824           0 :                                 aVCLGradient.SetEndColor(aTransColor);
    1825           0 :                                 aVCLGradient.SetAngle(0);
    1826           0 :                                 aVCLGradient.SetBorder(0);
    1827           0 :                                 aVCLGradient.SetOfsX(0);
    1828           0 :                                 aVCLGradient.SetOfsY(0);
    1829           0 :                                 aVCLGradient.SetStartIntensity(100);
    1830           0 :                                 aVCLGradient.SetEndIntensity(100);
    1831           0 :                                 aVCLGradient.SetSteps(2);
    1832             : 
    1833             :                                 // render it to VCL
    1834             :                                 mpOutputDevice->DrawTransparent(
    1835             :                                     aContentMetafile, aPrimitiveRectangle.TopLeft(),
    1836           0 :                                     aPrimitiveRectangle.GetSize(), aVCLGradient);
    1837             :                             }
    1838             :                         }
    1839             :                     }
    1840             : 
    1841           0 :                     break;
    1842             :                 }
    1843             :                 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
    1844             :                 {
    1845             :                     // for metafile: Need to examine what the pure vcl version is doing here actually
    1846             :                     // - uses DrawTransparent with metafile for content and a gradient
    1847             :                     // i can detect this here with checking the gradient part for a single
    1848             :                     // FillGradientPrimitive2D and reconstruct the gradient.
    1849             :                     // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually
    1850             :                     // do that in stripes, else RenderTransparencePrimitive2D may just be used
    1851           0 :                     const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
    1852           0 :                     const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren();
    1853           0 :                     const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence();
    1854             : 
    1855           0 :                     if(rContent.hasElements() && rTransparence.hasElements())
    1856             :                     {
    1857             :                         // try to identify a single FillGradientPrimitive2D in the
    1858             :                         // transparence part of the primitive
    1859           0 :                         const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
    1860             :                         static bool bForceToBigTransparentVDev(false);
    1861             : 
    1862           0 :                         if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength())
    1863             :                         {
    1864           0 :                             const primitive2d::Primitive2DReference xReference(rTransparence[0]);
    1865           0 :                             pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
    1866             :                         }
    1867             : 
    1868             :                         // Check also for correct ID to exclude derived implementations
    1869           0 :                         if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
    1870             :                         {
    1871             :                             // various content, create content-metafile
    1872           0 :                             GDIMetaFile aContentMetafile;
    1873           0 :                             const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
    1874             : 
    1875             :                             // re-create a VCL-gradient from FillGradientPrimitive2D
    1876           0 :                             Gradient aVCLGradient;
    1877           0 :                             impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
    1878             : 
    1879             :                             // render it to VCL
    1880             :                             mpOutputDevice->DrawTransparent(
    1881             :                                 aContentMetafile, aPrimitiveRectangle.TopLeft(),
    1882           0 :                                 aPrimitiveRectangle.GetSize(), aVCLGradient);
    1883             :                         }
    1884             :                         else
    1885             :                         {
    1886             :                             // sub-transparence group. Draw to VDev first.
    1887             :                             // this may get refined to tiling when resolution is too big here
    1888             : 
    1889             :                             // need to avoid switching off MapMode stuff here; maybe need another
    1890             :                             // tooling class, cannot just do the same as with the pixel renderer.
    1891             :                             // Need to experiment...
    1892             : 
    1893             :                             // Okay, basic implementation finished and tested. The DPI stuff was hard
    1894             :                             // and not easy to find out that it's needed.
    1895             :                             // Since this will not yet happen normally (as long as noone constructs
    1896             :                             // transparence primitives with non-trivial transparence content) i will for now not
    1897             :                             // refine to tiling here.
    1898             : 
    1899           0 :                             basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
    1900           0 :                             aViewRange.transform(maCurrentTransformation);
    1901             :                             const Rectangle aRectLogic(
    1902           0 :                                 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
    1903           0 :                                 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
    1904           0 :                             const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
    1905           0 :                             Size aSizePixel(aRectPixel.GetSize());
    1906           0 :                             const Point aEmptyPoint;
    1907           0 :                             VirtualDevice aBufferDevice;
    1908           0 :                             const sal_uInt32 nMaxQuadratPixels(500000);
    1909           0 :                             const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
    1910           0 :                             double fReduceFactor(1.0);
    1911             : 
    1912           0 :                             if(nViewVisibleArea > nMaxQuadratPixels)
    1913             :                             {
    1914             :                                 // reduce render size
    1915           0 :                                 fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea);
    1916           0 :                                 aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor),
    1917           0 :                                     basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor));
    1918             :                             }
    1919             : 
    1920           0 :                             if(aBufferDevice.SetOutputSizePixel(aSizePixel))
    1921             :                             {
    1922             :                                 // create and set MapModes for target devices
    1923           0 :                                 MapMode aNewMapMode(mpOutputDevice->GetMapMode());
    1924           0 :                                 aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
    1925           0 :                                 aBufferDevice.SetMapMode(aNewMapMode);
    1926             : 
    1927             :                                 // prepare view transformation for target renderers
    1928             :                                 // ATTENTION! Need to apply another scaling because of the potential DPI differences
    1929             :                                 // between Printer and VDev (mpOutputDevice and aBufferDevice here).
    1930             :                                 // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
    1931           0 :                                 basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
    1932           0 :                                 const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
    1933           0 :                                 const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
    1934           0 :                                 const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
    1935           0 :                                 const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
    1936             : 
    1937           0 :                                 if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
    1938             :                                 {
    1939           0 :                                     aViewTransform.scale(fDPIXChange, fDPIYChange);
    1940             :                                 }
    1941             : 
    1942             :                                 // also take scaling from Size reduction into acount
    1943           0 :                                 if(!basegfx::fTools::equal(fReduceFactor, 1.0))
    1944             :                                 {
    1945           0 :                                     aViewTransform.scale(fReduceFactor, fReduceFactor);
    1946             :                                 }
    1947             : 
    1948             :                                 // create view information and pixel renderer. Reuse known ViewInformation
    1949             :                                 // except new transformation and range
    1950             :                                 const geometry::ViewInformation2D aViewInfo(
    1951           0 :                                     getViewInformation2D().getObjectTransformation(),
    1952             :                                     aViewTransform,
    1953             :                                     aViewRange,
    1954           0 :                                     getViewInformation2D().getVisualizedPage(),
    1955           0 :                                     getViewInformation2D().getViewTime(),
    1956           0 :                                     getViewInformation2D().getExtendedInformationSequence());
    1957             : 
    1958           0 :                                 VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
    1959             : 
    1960             :                                 // draw content using pixel renderer
    1961           0 :                                 aBufferProcessor.process(rContent);
    1962           0 :                                 const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
    1963             : 
    1964             :                                 // draw transparence using pixel renderer
    1965           0 :                                 aBufferDevice.Erase();
    1966           0 :                                 aBufferProcessor.process(rTransparence);
    1967           0 :                                 const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
    1968             : 
    1969             :                                 // paint
    1970             :                                 mpOutputDevice->DrawBitmapEx(
    1971             :                                     aRectLogic.TopLeft(),
    1972             :                                     aRectLogic.GetSize(),
    1973           0 :                                     BitmapEx(aBmContent, aBmAlpha));
    1974           0 :                             }
    1975             :                         }
    1976             :                     }
    1977             : 
    1978           0 :                     break;
    1979             :                 }
    1980             :                 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
    1981             :                 {
    1982             :                     // use default transform group pocessing
    1983           1 :                     RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
    1984           1 :                     break;
    1985             :                 }
    1986             :                 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
    1987             :                 {
    1988             :                     // new XDrawPage for ViewInformation2D
    1989           0 :                     RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
    1990           0 :                     break;
    1991             :                 }
    1992             :                 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
    1993             :                 {
    1994             :                     // use default marker array pocessing
    1995           0 :                     RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
    1996           0 :                     break;
    1997             :                 }
    1998             :                 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
    1999             :                 {
    2000             :                     // use default point array pocessing
    2001           0 :                     RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
    2002           0 :                     break;
    2003             :                 }
    2004             :                 case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
    2005             :                 {
    2006             :                     // structured tag primitive
    2007           0 :                     const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
    2008           0 :                     const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
    2009           0 :                     const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
    2010             : 
    2011           0 :                     if(mpPDFExtOutDevData &&  bTagUsed)
    2012             :                     {
    2013             :                         // write start tag
    2014           0 :                         mpPDFExtOutDevData->BeginStructureElement(rTagElement);
    2015             :                     }
    2016             : 
    2017             :                     // proccess children normally
    2018           0 :                     process(rStructureTagCandidate.getChildren());
    2019             : 
    2020           0 :                     if(mpPDFExtOutDevData &&  bTagUsed)
    2021             :                     {
    2022             :                         // write end tag
    2023           0 :                         mpPDFExtOutDevData->EndStructureElement();
    2024             :                     }
    2025             : 
    2026           0 :                     break;
    2027             :                 }
    2028             :                 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
    2029             :                 {
    2030           0 :                     RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
    2031           0 :                     break;
    2032             :                 }
    2033             :                 default :
    2034             :                 {
    2035             :                     // process recursively
    2036          32 :                     process(rCandidate.get2DDecomposition(getViewInformation2D()));
    2037          32 :                     break;
    2038             :                 }
    2039             :             }
    2040          93 :         }
    2041             :     } // end of namespace processor2d
    2042          66 : } // end of namespace drawinglayer
    2043             : 
    2044             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10