LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/processor2d - vclprocessor2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 139 702 19.8 %
Date: 2012-12-27 Functions: 10 26 38.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <comphelper/string.hxx>
      21             : #include <drawinglayer/processor2d/vclprocessor2d.hxx>
      22             : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
      23             : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
      24             : #include <tools/debug.hxx>
      25             : #include <vcl/outdev.hxx>
      26             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      27             : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
      28             : #include <vclhelperbitmaptransform.hxx>
      29             : #include <basegfx/polygon/b2dpolygontools.hxx>
      30             : #include <vclhelperbitmaprender.hxx>
      31             : #include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
      32             : #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
      33             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      34             : #include <vclhelpergradient.hxx>
      35             : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
      36             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      37             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      38             : #include <vclhelperbufferdevice.hxx>
      39             : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
      40             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      41             : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
      42             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      43             : #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
      44             : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
      45             : #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
      46             : #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
      47             : #include <tools/diagnose_ex.h>
      48             : #include <rtl/ustrbuf.hxx>
      49             : #include <vcl/metric.hxx>
      50             : #include <drawinglayer/primitive2d/textenumsprimitive2d.hxx>
      51             : #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
      52             : #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
      53             : #include <basegfx/color/bcolor.hxx>
      54             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      55             : 
      56             : #include "getdigitlanguage.hxx"
      57             : 
      58             : //////////////////////////////////////////////////////////////////////////////
      59             : // control support
      60             : 
      61             : #include <com/sun/star/awt/XWindow2.hpp>
      62             : #include <com/sun/star/awt/PosSize.hpp>
      63             : #include <com/sun/star/awt/XView.hpp>
      64             : #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
      65             : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
      66             : 
      67             : //////////////////////////////////////////////////////////////////////////////
      68             : // for test, can be removed again
      69             : 
      70             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      71             : #include <basegfx/polygon/b2dtrapezoid.hxx>
      72             : 
      73             : //////////////////////////////////////////////////////////////////////////////
      74             : 
      75             : using namespace com::sun::star;
      76             : 
      77             : //////////////////////////////////////////////////////////////////////////////
      78             : 
      79             : namespace
      80             : {
      81           0 :     sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA, const basegfx::BColor& rColorB, double fDelta, double fDiscreteUnit)
      82             :     {
      83             :         // use color distance, assume to do every color step
      84           0 :         sal_uInt32 nSteps(basegfx::fround(rColorA.getDistance(rColorB) * 255.0));
      85             : 
      86           0 :         if(nSteps)
      87             :         {
      88             :             // calc discrete length to change color each disctete unit (pixel)
      89           0 :             const sal_uInt32 nDistSteps(basegfx::fround(fDelta / fDiscreteUnit));
      90             : 
      91           0 :             nSteps = std::min(nSteps, nDistSteps);
      92             :         }
      93             : 
      94             :         // reduce quality to 3 discrete units or every 3rd color step for rendering
      95           0 :         nSteps /= 2;
      96             : 
      97             :         // roughly cut when too big or too small (not full quality, reduce complexity)
      98           0 :         nSteps = std::min(nSteps, sal_uInt32(255));
      99           0 :         nSteps = std::max(nSteps, sal_uInt32(1));
     100             : 
     101           0 :         return nSteps;
     102             :     }
     103             : } // end of anonymous namespace
     104             : 
     105             : //////////////////////////////////////////////////////////////////////////////
     106             : 
     107             : namespace drawinglayer
     108             : {
     109             :     namespace processor2d
     110             :     {
     111             :         //////////////////////////////////////////////////////////////////////////////
     112             :         // UNO class usages
     113             :         using ::com::sun::star::uno::Reference;
     114             :         using ::com::sun::star::uno::UNO_QUERY;
     115             :         using ::com::sun::star::uno::UNO_QUERY_THROW;
     116             :         using ::com::sun::star::uno::Exception;
     117             :         using ::com::sun::star::awt::XView;
     118             :         using ::com::sun::star::awt::XGraphics;
     119             :         using ::com::sun::star::awt::XWindow;
     120             :         using ::com::sun::star::awt::PosSize::POSSIZE;
     121             : 
     122             :         //////////////////////////////////////////////////////////////////////////////
     123             :         // rendering support
     124             : 
     125             :         // directdraw of text simple portion or decorated portion primitive. When decorated, all the extra
     126             :         // information is translated to VCL parameters and set at the font.
     127             :         // Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring
     128             :         // for VCL)
     129           7 :         void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
     130             :         {
     131             :             // decompose matrix to have position and size of text
     132           7 :             basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform());
     133           7 :             basegfx::B2DVector aFontScaling, aTranslate;
     134             :             double fRotate, fShearX;
     135           7 :             aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX);
     136           7 :             bool bPrimitiveAccepted(false);
     137             : 
     138           7 :             if(basegfx::fTools::equalZero(fShearX))
     139             :             {
     140           7 :                 if(basegfx::fTools::less(aFontScaling.getX(), 0.0) && basegfx::fTools::less(aFontScaling.getY(), 0.0))
     141             :                 {
     142             :                     // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
     143             :                     // be expressed as rotation by PI. Use this since the Font rendering will not
     144             :                     // apply the negative scales in any form
     145           0 :                     aFontScaling = basegfx::absolute(aFontScaling);
     146           0 :                     fRotate += F_PI;
     147             :                 }
     148             : 
     149           7 :                 if(basegfx::fTools::more(aFontScaling.getX(), 0.0) && basegfx::fTools::more(aFontScaling.getY(), 0.0))
     150             :                 {
     151             :                     // Get the VCL font (use FontHeight as FontWidth)
     152             :                     Font aFont(primitive2d::getVclFontFromFontAttribute(
     153           7 :                         rTextCandidate.getFontAttribute(),
     154             :                         aFontScaling.getX(),
     155             :                         aFontScaling.getY(),
     156             :                         fRotate,
     157          14 :                         rTextCandidate.getLocale()));
     158             : 
     159             :                     // handle additional font attributes
     160             :                     const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP =
     161           7 :                         dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D*>( &rTextCandidate );
     162             : 
     163           7 :                     if( pTCPP != NULL )
     164             :                     {
     165             : 
     166             :                         // set the color of text decorations
     167           0 :                         const basegfx::BColor aTextlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getTextlineColor());
     168           0 :                         mpOutputDevice->SetTextLineColor( Color(aTextlineColor) );
     169             : 
     170             :                         // set Overline attribute
     171           0 :                         const FontUnderline eFontOverline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontOverline() ));
     172           0 :                         if( eFontOverline != UNDERLINE_NONE )
     173             :                         {
     174           0 :                             aFont.SetOverline( eFontOverline );
     175           0 :                             const basegfx::BColor aOverlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getOverlineColor());
     176           0 :                             mpOutputDevice->SetOverlineColor( Color(aOverlineColor) );
     177           0 :                             if( pTCPP->getWordLineMode() )
     178           0 :                                 aFont.SetWordLineMode( true );
     179             :                         }
     180             : 
     181             :                         // set Underline attribute
     182           0 :                         const FontUnderline eFontUnderline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontUnderline() ));
     183           0 :                         if( eFontUnderline != UNDERLINE_NONE )
     184             :                         {
     185           0 :                             aFont.SetUnderline( eFontUnderline );
     186           0 :                             if( pTCPP->getWordLineMode() )
     187           0 :                                 aFont.SetWordLineMode( true );
     188             : //TODO: ???                 if( pTCPP->getUnderlineAbove() )
     189             : //                              aFont.SetUnderlineAbove( true );
     190             :                         }
     191             : 
     192             :                         // set Strikeout attribute
     193           0 :                         const FontStrikeout eFontStrikeout(primitive2d::mapTextStrikeoutToFontStrikeout(pTCPP->getTextStrikeout()));
     194             : 
     195           0 :                         if( eFontStrikeout != STRIKEOUT_NONE )
     196           0 :                             aFont.SetStrikeout( eFontStrikeout );
     197             : 
     198             :                         // set EmphasisMark attribute
     199           0 :                         FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE;
     200           0 :                         switch( pTCPP->getTextEmphasisMark() )
     201             :                         {
     202             :                             default:
     203             :                                 DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getTextEmphasisMark() );
     204             :                                 // fall through
     205           0 :                             case primitive2d::TEXT_EMPHASISMARK_NONE:   eFontEmphasisMark = EMPHASISMARK_NONE; break;
     206           0 :                             case primitive2d::TEXT_EMPHASISMARK_DOT:    eFontEmphasisMark = EMPHASISMARK_DOT; break;
     207           0 :                             case primitive2d::TEXT_EMPHASISMARK_CIRCLE: eFontEmphasisMark = EMPHASISMARK_CIRCLE; break;
     208           0 :                             case primitive2d::TEXT_EMPHASISMARK_DISC:   eFontEmphasisMark = EMPHASISMARK_DISC; break;
     209           0 :                             case primitive2d::TEXT_EMPHASISMARK_ACCENT: eFontEmphasisMark = EMPHASISMARK_ACCENT; break;
     210             :                         }
     211             : 
     212           0 :                         if( eFontEmphasisMark != EMPHASISMARK_NONE )
     213             :                         {
     214             :                             DBG_ASSERT( (pTCPP->getEmphasisMarkAbove() != pTCPP->getEmphasisMarkBelow()),
     215             :                                 "DrawingLayer: Bad EmphasisMark position!" );
     216           0 :                             if( pTCPP->getEmphasisMarkAbove() )
     217           0 :                                 eFontEmphasisMark |= EMPHASISMARK_POS_ABOVE;
     218             :                             else
     219           0 :                                 eFontEmphasisMark |= EMPHASISMARK_POS_BELOW;
     220           0 :                             aFont.SetEmphasisMark( eFontEmphasisMark );
     221             :                         }
     222             : 
     223             :                         // set Relief attribute
     224           0 :                         FontRelief eFontRelief = RELIEF_NONE;
     225           0 :                         switch( pTCPP->getTextRelief() )
     226             :                         {
     227             :                             default:
     228             :                                 DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getTextRelief() );
     229             :                                 // fall through
     230           0 :                             case primitive2d::TEXT_RELIEF_NONE:     eFontRelief = RELIEF_NONE; break;
     231           0 :                             case primitive2d::TEXT_RELIEF_EMBOSSED: eFontRelief = RELIEF_EMBOSSED; break;
     232           0 :                             case primitive2d::TEXT_RELIEF_ENGRAVED: eFontRelief = RELIEF_ENGRAVED; break;
     233             :                         }
     234             : 
     235           0 :                         if( eFontRelief != RELIEF_NONE )
     236           0 :                             aFont.SetRelief( eFontRelief );
     237             : 
     238             :                         // set Shadow attribute
     239           0 :                         if( pTCPP->getShadow() )
     240           0 :                             aFont.SetShadow( true );
     241             :                     }
     242             : 
     243             :                     // create transformed integer DXArray in view coordinate system
     244           7 :                     ::std::vector< sal_Int32 > aTransformedDXArray;
     245             : 
     246           7 :                     if(rTextCandidate.getDXArray().size())
     247             :                     {
     248           5 :                         aTransformedDXArray.reserve(rTextCandidate.getDXArray().size());
     249           5 :                         const basegfx::B2DVector aPixelVector(maCurrentTransformation * basegfx::B2DVector(1.0, 0.0));
     250           5 :                         const double fPixelVectorFactor(aPixelVector.getLength());
     251             : 
     252         150 :                         for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin());
     253         100 :                             aStart != rTextCandidate.getDXArray().end(); ++aStart)
     254             :                         {
     255          45 :                             aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorFactor));
     256           5 :                         }
     257             :                     }
     258             : 
     259             :                     // set parameters and paint text snippet
     260           7 :                     const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
     261           7 :                     const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
     262           7 :                     const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
     263           7 :                     const sal_uInt32 nOldLayoutMode(mpOutputDevice->GetLayoutMode());
     264             : 
     265           7 :                     if(rTextCandidate.getFontAttribute().getRTL())
     266             :                     {
     267           0 :                         sal_uInt32 nRTLLayoutMode(nOldLayoutMode & ~(TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG));
     268           0 :                         nRTLLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT;
     269           0 :                         mpOutputDevice->SetLayoutMode(nRTLLayoutMode);
     270             :                     }
     271             : 
     272           7 :                     mpOutputDevice->SetFont(aFont);
     273           7 :                     mpOutputDevice->SetTextColor(Color(aRGBFontColor));
     274             : 
     275           7 :                     String aText( rTextCandidate.getText() );
     276           7 :                     xub_StrLen nPos = rTextCandidate.getTextPosition();
     277           7 :                     xub_StrLen nLen = rTextCandidate.getTextLength();
     278             : 
     279           7 :                     sal_Int32* pDXArray = aTransformedDXArray.size() ? &(aTransformedDXArray[0]) : NULL ;
     280             : 
     281           7 :                     if ( rTextCandidate.isFilled() )
     282             :                     {
     283           0 :                         basegfx::B2DVector aOldFontScaling, aOldTranslate;
     284             :                         double fOldRotate, fOldShearX;
     285           0 :                         rTextCandidate.getTextTransform().decompose(aOldFontScaling, aOldTranslate, fOldRotate, fOldShearX);
     286             : 
     287           0 :                         long nWidthToFill = static_cast<long>(rTextCandidate.getWidthToFill( ) * aFontScaling.getX() / aOldFontScaling.getX());
     288             : 
     289             :                         long nWidth = mpOutputDevice->GetTextArray(
     290           0 :                             rTextCandidate.getText(), pDXArray, 0, 1 );
     291           0 :                         long nChars = 2;
     292           0 :                         if ( nWidth )
     293           0 :                             nChars = nWidthToFill / nWidth;
     294             : 
     295           0 :                         rtl::OUStringBuffer aFilled;
     296           0 :                         comphelper::string::padToLength(aFilled, (sal_uInt16)nChars, aText.GetChar(0));
     297           0 :                         aText = aFilled.makeStringAndClear();
     298           0 :                         nPos = 0;
     299           0 :                         nLen = nChars;
     300             :                     }
     301             : 
     302           7 :                     if(!aTransformedDXArray.empty())
     303             :                     {
     304             :                         mpOutputDevice->DrawTextArray(
     305             :                             aStartPoint,
     306             :                             aText,
     307             :                             pDXArray,
     308             :                             nPos,
     309           5 :                             nLen);
     310             :                     }
     311             :                     else
     312             :                     {
     313             :                         mpOutputDevice->DrawText(
     314             :                             aStartPoint,
     315             :                             aText,
     316             :                             nPos,
     317           2 :                             nLen);
     318             :                     }
     319             : 
     320           7 :                     if(rTextCandidate.getFontAttribute().getRTL())
     321             :                     {
     322           0 :                         mpOutputDevice->SetLayoutMode(nOldLayoutMode);
     323             :                     }
     324             : 
     325           7 :                     bPrimitiveAccepted = true;
     326             :                 }
     327             :             }
     328             : 
     329           7 :             if(!bPrimitiveAccepted)
     330             :             {
     331             :                 // let break down
     332           0 :                 process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
     333           7 :             }
     334           7 :         }
     335             : 
     336             :         // direct draw of hairline
     337        2415 :         void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased)
     338             :         {
     339        2415 :             const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
     340        2415 :             mpOutputDevice->SetLineColor(Color(aHairlineColor));
     341        2415 :             mpOutputDevice->SetFillColor();
     342             : 
     343        2415 :             basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
     344        2415 :             aLocalPolygon.transform(maCurrentTransformation);
     345             : 
     346             :             static bool bCheckTrapezoidDecomposition(false);
     347             :             static bool bShowOutlinesThere(false);
     348        2415 :             if(bCheckTrapezoidDecomposition)
     349             :             {
     350             :                 // clip against discrete ViewPort
     351           0 :                 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
     352             :                 basegfx::B2DPolyPolygon aLocalPolyPolygon(basegfx::tools::clipPolygonOnRange(
     353           0 :                     aLocalPolygon, rDiscreteViewport, true, false));
     354             : 
     355           0 :                 if(aLocalPolyPolygon.count())
     356             :                 {
     357             :                     // subdivide
     358             :                     aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
     359           0 :                         aLocalPolyPolygon, 0.5);
     360             : 
     361             :                     // trapezoidize
     362             :                     static double fLineWidth(2.0);
     363           0 :                     basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
     364           0 :                     basegfx::tools::createLineTrapezoidFromB2DPolyPolygon(aB2DTrapezoidVector, aLocalPolyPolygon, fLineWidth);
     365             : 
     366           0 :                     const sal_uInt32 nCount(aB2DTrapezoidVector.size());
     367             : 
     368           0 :                     if(nCount)
     369             :                     {
     370           0 :                         basegfx::BColor aInvPolygonColor(aHairlineColor);
     371           0 :                         aInvPolygonColor.invert();
     372             : 
     373           0 :                         for(sal_uInt32 a(0); a < nCount; a++)
     374             :                         {
     375           0 :                             const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
     376             : 
     377           0 :                             if(bShowOutlinesThere)
     378             :                             {
     379           0 :                                 mpOutputDevice->SetFillColor(Color(aHairlineColor));
     380           0 :                                 mpOutputDevice->SetLineColor();
     381             :                             }
     382             : 
     383           0 :                             mpOutputDevice->DrawPolygon(aTempPolygon);
     384             : 
     385           0 :                             if(bShowOutlinesThere)
     386             :                             {
     387           0 :                                 mpOutputDevice->SetFillColor();
     388           0 :                                 mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
     389           0 :                                 mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
     390             :                             }
     391           0 :                         }
     392           0 :                     }
     393           0 :                 }
     394             :             }
     395             :             else
     396             :             {
     397        2415 :                 if(bPixelBased && getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete())
     398             :                 {
     399             :                     // #i98289#
     400             :                     // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete
     401             :                     // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since
     402             :                     // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This
     403             :                     // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering.
     404           0 :                     aLocalPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon);
     405             :                 }
     406             : 
     407        2415 :                 mpOutputDevice->DrawPolyLine(aLocalPolygon, 0.0);
     408        2415 :             }
     409        2415 :         }
     410             : 
     411             :         // direct draw of transformed BitmapEx primitive
     412           8 :         void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
     413             :         {
     414             :             // create local transform
     415           8 :             basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
     416           8 :             BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
     417           8 :             bool bPainted(false);
     418             : 
     419           8 :             if(maBColorModifierStack.count())
     420             :             {
     421           0 :                 aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
     422             : 
     423           0 :                 if(aBitmapEx.IsEmpty())
     424             :                 {
     425             :                     // color gets completely replaced, get it
     426           0 :                     const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
     427           0 :                     basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
     428           0 :                     aPolygon.transform(aLocalTransform);
     429             : 
     430           0 :                     mpOutputDevice->SetFillColor(Color(aModifiedColor));
     431           0 :                     mpOutputDevice->SetLineColor();
     432           0 :                     mpOutputDevice->DrawPolygon(aPolygon);
     433             : 
     434           0 :                     bPainted = true;
     435             :                 }
     436             :             }
     437             : 
     438           8 :             if(!bPainted)
     439             :             {
     440             :                 static bool bForceUseOfOwnTransformer(false);
     441             :                 static bool bUseGraphicManager(true);
     442             : 
     443             :                 // decompose matrix to check for shear, rotate and mirroring
     444           8 :                 basegfx::B2DVector aScale, aTranslate;
     445             :                 double fRotate, fShearX;
     446           8 :                 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
     447             : 
     448           8 :                 if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX))
     449             :                 {
     450           8 :                     if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate))
     451             :                     {
     452           0 :                         RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform);
     453             :                     }
     454             :                     else
     455             :                     {
     456           8 :                         RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform);
     457             :                     }
     458             :                 }
     459             :                 else
     460             :                 {
     461           0 :                     if(!aBitmapEx.IsTransparent() && (!basegfx::fTools::equalZero(fShearX) || !basegfx::fTools::equalZero(fRotate)))
     462             :                     {
     463             :                         // parts will be uncovered, extend aBitmapEx with a mask bitmap
     464           0 :                         const Bitmap aContent(aBitmapEx.GetBitmap());
     465           0 :                         aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1));
     466             :                     }
     467             : 
     468           0 :                     RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform);
     469           8 :                 }
     470           8 :             }
     471           8 :         }
     472             : 
     473           0 :         void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate)
     474             :         {
     475           0 :             const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap());
     476           0 :             bool bPrimitiveAccepted(false);
     477             : 
     478           0 :             if(rFillBitmapAttribute.getTiling())
     479             :             {
     480             :                 // decompose matrix to check for shear, rotate and mirroring
     481           0 :                 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation());
     482           0 :                 basegfx::B2DVector aScale, aTranslate;
     483             :                 double fRotate, fShearX;
     484           0 :                 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
     485             : 
     486           0 :                 if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX))
     487             :                 {
     488             :                     // no shear or rotate, draw direct in pixel coordinates
     489           0 :                     bPrimitiveAccepted = true;
     490           0 :                     BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmapEx());
     491           0 :                     bool bPainted(false);
     492             : 
     493           0 :                     if(maBColorModifierStack.count())
     494             :                     {
     495           0 :                         aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
     496             : 
     497           0 :                         if(aBitmapEx.IsEmpty())
     498             :                         {
     499             :                             // color gets completely replaced, get it
     500           0 :                             const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
     501           0 :                             basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
     502           0 :                             aPolygon.transform(aLocalTransform);
     503             : 
     504           0 :                             mpOutputDevice->SetFillColor(Color(aModifiedColor));
     505           0 :                             mpOutputDevice->SetLineColor();
     506           0 :                             mpOutputDevice->DrawPolygon(aPolygon);
     507             : 
     508           0 :                             bPainted = true;
     509             :                         }
     510             :                     }
     511             : 
     512           0 :                     if(!bPainted)
     513             :                     {
     514           0 :                         const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY());
     515           0 :                         const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
     516           0 :                         const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY())));
     517           0 :                         const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY())));
     518             : 
     519           0 :                         const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft());
     520           0 :                         const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()));
     521           0 :                         const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY())));
     522           0 :                         const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY())));
     523             : 
     524           0 :                         sal_Int32 nOWidth(aObjBR.X() - aObjTL.X());
     525           0 :                         sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y());
     526             : 
     527             :                         // only do something when object has a size in discrete units
     528           0 :                         if(nOWidth > 0 && nOHeight > 0)
     529             :                         {
     530           0 :                             sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X());
     531           0 :                             sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y());
     532             : 
     533             :                             // only do something when bitmap fill has a size in discrete units
     534           0 :                             if(nBWidth > 0 && nBHeight > 0)
     535             :                             {
     536           0 :                                 sal_Int32 nBLeft(aBmpTL.X());
     537           0 :                                 sal_Int32 nBTop(aBmpTL.Y());
     538             : 
     539           0 :                                 if(nBLeft > aObjTL.X())
     540             :                                 {
     541           0 :                                     nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth;
     542             :                                 }
     543             : 
     544           0 :                                 if(nBLeft + nBWidth <= aObjTL.X())
     545             :                                 {
     546           0 :                                     nBLeft -= (nBLeft / nBWidth) * nBWidth;
     547             :                                 }
     548             : 
     549           0 :                                 if(nBTop > aObjTL.Y())
     550             :                                 {
     551           0 :                                     nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight;
     552             :                                 }
     553             : 
     554           0 :                                 if(nBTop + nBHeight <= aObjTL.Y())
     555             :                                 {
     556           0 :                                     nBTop -= (nBTop / nBHeight) * nBHeight;
     557             :                                 }
     558             : 
     559             :                                 // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it
     560             :                                 // in vcl many times, create a size-optimized version
     561           0 :                                 const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
     562             : 
     563           0 :                                 if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel())
     564             :                                 {
     565           0 :                                     aBitmapEx.Scale(aNeededBitmapSizePixel);
     566             :                                 }
     567             : 
     568             :                                 // prepare OutDev
     569           0 :                                 const Point aEmptyPoint(0, 0);
     570           0 :                                 const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel());
     571           0 :                                 const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
     572           0 :                                 mpOutputDevice->EnableMapMode(false);
     573             : 
     574           0 :                                 for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth)
     575             :                                 {
     576           0 :                                     for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight)
     577             :                                     {
     578           0 :                                         const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel);
     579             : 
     580           0 :                                         if(aOutRectPixel.IsOver(aVisiblePixel))
     581             :                                         {
     582           0 :                                             mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
     583             :                                         }
     584             :                                     }
     585             :                                 }
     586             : 
     587             :                                 // restore OutDev
     588           0 :                                 mpOutputDevice->EnableMapMode(bWasEnabled);
     589             :                             }
     590           0 :                         }
     591           0 :                     }
     592           0 :                 }
     593             :             }
     594             : 
     595           0 :             if(!bPrimitiveAccepted)
     596             :             {
     597             :                 // do not accept, use decomposition
     598           0 :                 process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D()));
     599             :             }
     600           0 :         }
     601             : 
     602             :         // direct draw of gradient
     603           0 :         void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
     604             :         {
     605           0 :             const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
     606           0 :             basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
     607           0 :             basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
     608           0 :             basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
     609             : 
     610           0 :             if(aLocalPolyPolygon.count())
     611             :             {
     612           0 :                 aLocalPolyPolygon.transform(maCurrentTransformation);
     613             : 
     614           0 :                 if(aStartColor == aEndColor)
     615             :                 {
     616             :                     // no gradient at all, draw as polygon in AA and non-AA case
     617           0 :                     mpOutputDevice->SetLineColor();
     618           0 :                     mpOutputDevice->SetFillColor(Color(aStartColor));
     619           0 :                     mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
     620             :                 }
     621           0 :                 else if(getOptionsDrawinglayer().IsAntiAliasing())
     622             :                 {
     623             :                     // For AA, direct render has to be avoided since it uses XOR maskings which will not
     624             :                     // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is
     625             :                     // used
     626           0 :                     process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
     627             :                 }
     628             :                 else
     629             :                 {
     630             :                     impDrawGradientToOutDev(
     631           0 :                         *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
     632             :                         aStartColor, aEndColor, rGradient.getBorder(),
     633           0 :                         rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
     634             :                 }
     635           0 :             }
     636           0 :         }
     637             : 
     638             :         // direct draw of bitmap
     639           0 :         void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate)
     640             :         {
     641           0 :             bool bDone(false);
     642           0 :             const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon();
     643             : 
     644           0 :             if(rPolyPolygon.count())
     645             :             {
     646           0 :                 const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap();
     647           0 :                 const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
     648             : 
     649           0 :                 if(rBitmapEx.IsEmpty())
     650             :                 {
     651             :                     // empty bitmap, done
     652           0 :                     bDone = true;
     653             :                 }
     654             :                 else
     655             :                 {
     656             :                     // try to catch cases where the bitmap will be color-modified to a single
     657             :                     // color (e.g. shadow). This would NOT be optimizable with an transparence channel
     658             :                     // at the Bitmap which we do not have here. When this should change, this
     659             :                     // optimization has to be reworked accordingly.
     660           0 :                     const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count());
     661             : 
     662           0 :                     if(nBColorModifierStackCount)
     663             :                     {
     664           0 :                         const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1);
     665             : 
     666           0 :                         if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode())
     667             :                         {
     668             :                             // the bitmap fill is in unified color, so we can replace it with
     669             :                             // a single polygon fill. The form of the fill depends on tiling
     670           0 :                             if(rFillBitmapAttribute.getTiling())
     671             :                             {
     672             :                                 // with tiling, fill the whole PolyPolygon with the modifier color
     673           0 :                                 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon);
     674             : 
     675           0 :                                 aLocalPolyPolygon.transform(maCurrentTransformation);
     676           0 :                                 mpOutputDevice->SetLineColor();
     677           0 :                                 mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
     678           0 :                                 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
     679             :                             }
     680             :                             else
     681             :                             {
     682             :                                 // without tiling, only the area common to the bitmap tile and the
     683             :                                 // PolyPolygon is filled. Create the bitmap tile area in object
     684             :                                 // coordinates. For this, the object transformation needs to be created
     685             :                                 // from the already scaled PolyPolygon. The tile area in object
     686             :                                 // coordinates wil always be non-rotated, so it's not necessary to
     687             :                                 // work with a polygon here
     688           0 :                                 basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(),
     689           0 :                                     rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize());
     690           0 :                                 const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange());
     691           0 :                                 basegfx::B2DHomMatrix aNewObjectTransform;
     692             : 
     693           0 :                                 aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth());
     694           0 :                                 aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight());
     695           0 :                                 aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX());
     696           0 :                                 aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY());
     697           0 :                                 aTileRange.transform(aNewObjectTransform);
     698             : 
     699             :                                 // now clip the object polyPolygon against the tile range
     700             :                                 // to get the common area (OR)
     701           0 :                                 basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false);
     702             : 
     703           0 :                                 if(aTarget.count())
     704             :                                 {
     705           0 :                                     aTarget.transform(maCurrentTransformation);
     706           0 :                                     mpOutputDevice->SetLineColor();
     707           0 :                                     mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
     708           0 :                                     mpOutputDevice->DrawPolyPolygon(aTarget);
     709           0 :                                 }
     710             :                             }
     711             : 
     712           0 :                             bDone = true;
     713             :                         }
     714             :                     }
     715             :                 }
     716             :             }
     717             :             else
     718             :             {
     719             :                 // empty polyPolygon, done
     720           0 :                 bDone = true;
     721             :             }
     722             : 
     723           0 :             if(!bDone)
     724             :             {
     725             :                 // use default decomposition
     726           0 :                 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
     727             :             }
     728           0 :         }
     729             : 
     730             :         // direct draw of PolyPolygon with color
     731         180 :         void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate)
     732             :         {
     733         180 :             const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
     734         180 :             mpOutputDevice->SetFillColor(Color(aPolygonColor));
     735         180 :             mpOutputDevice->SetLineColor();
     736             : 
     737         180 :             basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
     738         180 :             aLocalPolyPolygon.transform(maCurrentTransformation);
     739             : 
     740             :             static bool bCheckTrapezoidDecomposition(false);
     741             :             static bool bShowOutlinesThere(false);
     742         180 :             if(bCheckTrapezoidDecomposition)
     743             :             {
     744             :                 // clip against discrete ViewPort
     745           0 :                 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
     746             :                 aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
     747           0 :                     aLocalPolyPolygon, rDiscreteViewport, true, false);
     748             : 
     749           0 :                 if(aLocalPolyPolygon.count())
     750             :                 {
     751             :                     // subdivide
     752             :                     aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
     753           0 :                         aLocalPolyPolygon, 0.5);
     754             : 
     755             :                     // trapezoidize
     756           0 :                     basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
     757           0 :                     basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon);
     758             : 
     759           0 :                     const sal_uInt32 nCount(aB2DTrapezoidVector.size());
     760             : 
     761           0 :                     if(nCount)
     762             :                     {
     763           0 :                         basegfx::BColor aInvPolygonColor(aPolygonColor);
     764           0 :                         aInvPolygonColor.invert();
     765             : 
     766           0 :                         for(sal_uInt32 a(0); a < nCount; a++)
     767             :                         {
     768           0 :                             const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
     769             : 
     770           0 :                             if(bShowOutlinesThere)
     771             :                             {
     772           0 :                                 mpOutputDevice->SetFillColor(Color(aPolygonColor));
     773           0 :                                 mpOutputDevice->SetLineColor();
     774             :                             }
     775             : 
     776           0 :                             mpOutputDevice->DrawPolygon(aTempPolygon);
     777             : 
     778           0 :                             if(bShowOutlinesThere)
     779             :                             {
     780           0 :                                 mpOutputDevice->SetFillColor();
     781           0 :                                 mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
     782           0 :                                 mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
     783             :                             }
     784           0 :                         }
     785           0 :                     }
     786             :                 }
     787             :             }
     788             :             else
     789             :             {
     790         180 :                 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
     791             : 
     792         180 :                 if(mnPolygonStrokePrimitive2D
     793           0 :                     && getOptionsDrawinglayer().IsAntiAliasing()
     794           0 :                     && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW))
     795             :                 {
     796             :                     // when AA is on and this filled polygons are the result of stroked line geometry,
     797             :                     // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
     798           0 :                     mpOutputDevice->SetFillColor();
     799           0 :                     mpOutputDevice->SetLineColor(Color(aPolygonColor));
     800           0 :                     const sal_uInt32 nCount(aLocalPolyPolygon.count());
     801             : 
     802           0 :                     for(sal_uInt32 a(0); a < nCount; a++)
     803             :                     {
     804           0 :                         mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
     805             :                     }
     806             :                 }
     807         180 :             }
     808         180 :         }
     809             : 
     810             :         // direct draw of MetaFile
     811           0 :         void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
     812             :         {
     813             :             // decompose matrix to check for shear, rotate and mirroring
     814           0 :             basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform());
     815           0 :             basegfx::B2DVector aScale, aTranslate;
     816             :             double fRotate, fShearX;
     817           0 :             aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
     818             : 
     819           0 :             if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
     820             :             {
     821             :                 // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can
     822             :                 // be expressed as rotation by PI. This needs to be done for Metafiles since
     823             :                 // these can be rotated, but not really mirrored
     824           0 :                 aScale = basegfx::absolute(aScale);
     825           0 :                 fRotate += F_PI;
     826             :             }
     827             : 
     828             :             // get BoundRect
     829           0 :             basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D()));
     830           0 :             aOutlineRange.transform(maCurrentTransformation);
     831             : 
     832             :             // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three
     833             :             // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile
     834             :             // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use
     835             :             // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic
     836             :             // units e.g. when creating a new MetaFile, but since much huger value ranges are used
     837             :             // there typically will be okay for this compromize.
     838             :             Rectangle aDestRectView(
     839             :                 // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when
     840             :                 // looking for a standard conversion to rectangle (!)
     841           0 :                 (sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()),
     842           0 :                 (sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY()));
     843             : 
     844             :             // get metafile (copy it)
     845           0 :             GDIMetaFile aMetaFile;
     846             : 
     847           0 :             if(maBColorModifierStack.count())
     848             :             {
     849           0 :                 const basegfx::BColor aRGBBaseColor(0, 0, 0);
     850           0 :                 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
     851           0 :                 aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
     852             :             }
     853             :             else
     854             :             {
     855           0 :                 aMetaFile = rMetaCandidate.getMetaFile();
     856             :             }
     857             : 
     858             :             // rotation
     859           0 :             if(!basegfx::fTools::equalZero(fRotate))
     860             :             {
     861             :                 // #i103530#
     862             :                 // MetaFile::Rotate has no input parameter check, so the parameter needs to be
     863             :                 // well-aligned to the old range [0..3600] 10th degrees with inverse orientation
     864           0 :                 sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0));
     865             : 
     866           0 :                 while(nRotation < 0)
     867           0 :                     nRotation += 3600;
     868             : 
     869           0 :                 while(nRotation >= 3600)
     870           0 :                     nRotation -= 3600;
     871             : 
     872           0 :                 aMetaFile.Rotate(nRotation);
     873             :             }
     874             : 
     875             :             // Prepare target output size
     876           0 :             Size aDestSize(aDestRectView.GetSize());
     877             : 
     878           0 :             if(aDestSize.getWidth() && aDestSize.getHeight())
     879             :             {
     880             :                 // Get preferred Metafile output size. When it's very equal to the output size, it's probably
     881             :                 // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings
     882             :                 // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts)
     883           0 :                 const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode()));
     884             : 
     885           0 :                 if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth()))
     886             :                 {
     887           0 :                     aDestSize.setWidth(aPrefSize.getWidth());
     888             :                 }
     889             : 
     890           0 :                 if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight()))
     891             :                 {
     892           0 :                     aDestSize.setHeight(aPrefSize.getHeight());
     893             :                 }
     894             : 
     895             :                 // paint it
     896           0 :                 aMetaFile.WindStart();
     897           0 :                 aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize);
     898           0 :             }
     899           0 :         }
     900             : 
     901             :         // mask group. Force output to VDev and create mask from given mask
     902           0 :         void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate)
     903             :         {
     904           0 :             if(rMaskCandidate.getChildren().hasElements())
     905             :             {
     906           0 :                 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
     907             : 
     908           0 :                 if(aMask.count())
     909             :                 {
     910           0 :                     aMask.transform(maCurrentTransformation);
     911           0 :                     const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask));
     912           0 :                     impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
     913             : 
     914           0 :                     if(aBufferDevice.isVisible())
     915             :                     {
     916             :                         // remember last OutDev and set to content
     917           0 :                         OutputDevice* pLastOutputDevice = mpOutputDevice;
     918           0 :                         mpOutputDevice = &aBufferDevice.getContent();
     919             : 
     920             :                         // paint to it
     921           0 :                         process(rMaskCandidate.getChildren());
     922             : 
     923             :                         // back to old OutDev
     924           0 :                         mpOutputDevice = pLastOutputDevice;
     925             : 
     926             :                         // draw mask
     927           0 :                         if(getOptionsDrawinglayer().IsAntiAliasing())
     928             :                         {
     929             :                             // with AA, use 8bit AlphaMask to get nice borders
     930           0 :                             VirtualDevice& rTransparence = aBufferDevice.getTransparence();
     931           0 :                             rTransparence.SetLineColor();
     932           0 :                             rTransparence.SetFillColor(COL_BLACK);
     933           0 :                             rTransparence.DrawPolyPolygon(aMask);
     934             : 
     935             :                             // dump buffer to outdev
     936           0 :                             aBufferDevice.paint();
     937             :                         }
     938             :                         else
     939             :                         {
     940             :                             // No AA, use 1bit mask
     941           0 :                             VirtualDevice& rMask = aBufferDevice.getMask();
     942           0 :                             rMask.SetLineColor();
     943           0 :                             rMask.SetFillColor(COL_BLACK);
     944           0 :                             rMask.DrawPolyPolygon(aMask);
     945             : 
     946             :                             // dump buffer to outdev
     947           0 :                             aBufferDevice.paint();
     948             :                         }
     949           0 :                     }
     950           0 :                 }
     951             :             }
     952           0 :         }
     953             : 
     954             :         // modified color group. Force output to unified color.
     955           0 :         void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate)
     956             :         {
     957           0 :             if(rModifiedCandidate.getChildren().hasElements())
     958             :             {
     959           0 :                 maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
     960           0 :                 process(rModifiedCandidate.getChildren());
     961           0 :                 maBColorModifierStack.pop();
     962             :             }
     963           0 :         }
     964             : 
     965             :         // unified sub-transparence. Draw to VDev first.
     966           0 :         void VclProcessor2D::RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate)
     967             :         {
     968             :             static bool bForceToDecomposition(false);
     969             : 
     970           0 :             if(rTransCandidate.getChildren().hasElements())
     971             :             {
     972           0 :                 if(bForceToDecomposition)
     973             :                 {
     974             :                     // use decomposition
     975           0 :                     process(rTransCandidate.get2DDecomposition(getViewInformation2D()));
     976             :                 }
     977             :                 else
     978             :                 {
     979           0 :                     if(0.0 == rTransCandidate.getTransparence())
     980             :                     {
     981             :                         // no transparence used, so just use the content
     982           0 :                         process(rTransCandidate.getChildren());
     983             :                     }
     984           0 :                     else if(rTransCandidate.getTransparence() > 0.0 && rTransCandidate.getTransparence() < 1.0)
     985             :                     {
     986             :                         // transparence is in visible range
     987           0 :                         basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
     988           0 :                         aRange.transform(maCurrentTransformation);
     989           0 :                         impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
     990             : 
     991           0 :                         if(aBufferDevice.isVisible())
     992             :                         {
     993             :                             // remember last OutDev and set to content
     994           0 :                             OutputDevice* pLastOutputDevice = mpOutputDevice;
     995           0 :                             mpOutputDevice = &aBufferDevice.getContent();
     996             : 
     997             :                             // paint content to it
     998           0 :                             process(rTransCandidate.getChildren());
     999             : 
    1000             :                             // back to old OutDev
    1001           0 :                             mpOutputDevice = pLastOutputDevice;
    1002             : 
    1003             :                             // dump buffer to outdev using given transparence
    1004           0 :                             aBufferDevice.paint(rTransCandidate.getTransparence());
    1005           0 :                         }
    1006             :                     }
    1007             :                 }
    1008             :             }
    1009           0 :         }
    1010             : 
    1011             :         // sub-transparence group. Draw to VDev first.
    1012           0 :         void VclProcessor2D::RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate)
    1013             :         {
    1014           0 :             if(rTransCandidate.getChildren().hasElements())
    1015             :             {
    1016           0 :                 basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
    1017           0 :                 aRange.transform(maCurrentTransformation);
    1018           0 :                 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
    1019             : 
    1020           0 :                 if(aBufferDevice.isVisible())
    1021             :                 {
    1022             :                     // remember last OutDev and set to content
    1023           0 :                     OutputDevice* pLastOutputDevice = mpOutputDevice;
    1024           0 :                     mpOutputDevice = &aBufferDevice.getContent();
    1025             : 
    1026             :                     // paint content to it
    1027           0 :                     process(rTransCandidate.getChildren());
    1028             : 
    1029             :                     // set to mask
    1030           0 :                     mpOutputDevice = &aBufferDevice.getTransparence();
    1031             : 
    1032             :                     // when painting transparence masks, reset the color stack
    1033           0 :                     basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
    1034           0 :                     maBColorModifierStack = basegfx::BColorModifierStack();
    1035             : 
    1036             :                     // paint mask to it (always with transparence intensities, evtl. with AA)
    1037           0 :                     process(rTransCandidate.getTransparence());
    1038             : 
    1039             :                     // back to old color stack
    1040           0 :                     maBColorModifierStack = aLastBColorModifierStack;
    1041             : 
    1042             :                     // back to old OutDev
    1043           0 :                     mpOutputDevice = pLastOutputDevice;
    1044             : 
    1045             :                     // dump buffer to outdev
    1046           0 :                     aBufferDevice.paint();
    1047           0 :                 }
    1048             :             }
    1049           0 :         }
    1050             : 
    1051             :         // transform group.
    1052           1 :         void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate)
    1053             :         {
    1054             :             // remember current transformation and ViewInformation
    1055           1 :             const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation);
    1056           1 :             const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
    1057             : 
    1058             :             // create new transformations for CurrentTransformation
    1059             :             // and for local ViewInformation2D
    1060           1 :             maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation();
    1061             :             const geometry::ViewInformation2D aViewInformation2D(
    1062           1 :                 getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
    1063           1 :                 getViewInformation2D().getViewTransformation(),
    1064           1 :                 getViewInformation2D().getViewport(),
    1065           1 :                 getViewInformation2D().getVisualizedPage(),
    1066           1 :                 getViewInformation2D().getViewTime(),
    1067           3 :                 getViewInformation2D().getExtendedInformationSequence());
    1068           1 :             updateViewInformation(aViewInformation2D);
    1069             : 
    1070             :             // proccess content
    1071           1 :             process(rTransformCandidate.getChildren());
    1072             : 
    1073             :             // restore transformations
    1074           1 :             maCurrentTransformation = aLastCurrentTransformation;
    1075           1 :             updateViewInformation(aLastViewInformation2D);
    1076           1 :         }
    1077             : 
    1078             :         // new XDrawPage for ViewInformation2D
    1079           0 :         void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate)
    1080             :         {
    1081             :             // remember current transformation and ViewInformation
    1082           0 :             const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
    1083             : 
    1084             :             // create new local ViewInformation2D
    1085             :             const geometry::ViewInformation2D aViewInformation2D(
    1086           0 :                 getViewInformation2D().getObjectTransformation(),
    1087           0 :                 getViewInformation2D().getViewTransformation(),
    1088           0 :                 getViewInformation2D().getViewport(),
    1089           0 :                 rPagePreviewCandidate.getXDrawPage(),
    1090           0 :                 getViewInformation2D().getViewTime(),
    1091           0 :                 getViewInformation2D().getExtendedInformationSequence());
    1092           0 :             updateViewInformation(aViewInformation2D);
    1093             : 
    1094             :             // proccess decomposed content
    1095           0 :             process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
    1096             : 
    1097             :             // restore transformations
    1098           0 :             updateViewInformation(aLastViewInformation2D);
    1099           0 :         }
    1100             : 
    1101             :         // marker
    1102           0 :         void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate)
    1103             :         {
    1104             :             static bool bCheckCompleteMarkerDecompose(false);
    1105           0 :             if(bCheckCompleteMarkerDecompose)
    1106             :             {
    1107           0 :                 process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D()));
    1108           0 :                 return;
    1109             :             }
    1110             : 
    1111             :             // get data
    1112           0 :             const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions();
    1113           0 :             const sal_uInt32 nCount(rPositions.size());
    1114             : 
    1115           0 :             if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty())
    1116             :             {
    1117             :                 // get pixel size
    1118           0 :                 const BitmapEx& rMarker(rMarkArrayCandidate.getMarker());
    1119           0 :                 const Size aBitmapSize(rMarker.GetSizePixel());
    1120             : 
    1121           0 :                 if(aBitmapSize.Width() && aBitmapSize.Height())
    1122             :                 {
    1123             :                     // get discrete half size
    1124             :                     const basegfx::B2DVector aDiscreteHalfSize(
    1125           0 :                         (aBitmapSize.getWidth() - 1.0) * 0.5,
    1126           0 :                         (aBitmapSize.getHeight() - 1.0) * 0.5);
    1127           0 :                     const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
    1128             : 
    1129             :                     // do not forget evtl. moved origin in target device MapMode when
    1130             :                     // switching it off; it would be missing and lead to wrong positions.
    1131             :                     // All his could be done using logic sizes and coordinates, too, but
    1132             :                     // we want a 1:1 bitmap rendering here, so it's more safe and faster
    1133             :                     // to work with switching off MapMode usage completely.
    1134           0 :                     const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
    1135             : 
    1136           0 :                     mpOutputDevice->EnableMapMode(false);
    1137             : 
    1138           0 :                     for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); ++aIter)
    1139             :                     {
    1140           0 :                         const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize);
    1141           0 :                         const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY()));
    1142             : 
    1143           0 :                         mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker);
    1144           0 :                     }
    1145             : 
    1146           0 :                     mpOutputDevice->EnableMapMode(bWasEnabled);
    1147             :                 }
    1148             :             }
    1149             :         }
    1150             : 
    1151             :         // point
    1152           0 :         void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate)
    1153             :         {
    1154           0 :             const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions();
    1155           0 :             const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
    1156           0 :             const Color aVCLColor(aRGBColor);
    1157             : 
    1158           0 :             for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); ++aIter)
    1159             :             {
    1160           0 :                 const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter));
    1161           0 :                 const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY()));
    1162             : 
    1163           0 :                 mpOutputDevice->DrawPixel(aPos, aVCLColor);
    1164           0 :             }
    1165           0 :         }
    1166             : 
    1167          30 :         void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate)
    1168             :         {
    1169             :             // #i101491# method restructured to clearly use the DrawPolyLine
    1170             :             // calls starting from a deined line width
    1171          30 :             const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute();
    1172          30 :             const double fLineWidth(rLineAttribute.getWidth());
    1173          30 :             bool bDone(false);
    1174             : 
    1175          30 :             if(basegfx::fTools::more(fLineWidth, 0.0))
    1176             :             {
    1177          12 :                 const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0));
    1178          12 :                 const double fDiscreteLineWidth(aDiscreteUnit.getLength());
    1179          12 :                 const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute();
    1180          12 :                 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
    1181          12 :                 basegfx::B2DPolyPolygon aHairlinePolyPolygon;
    1182             : 
    1183          12 :                 mpOutputDevice->SetLineColor(Color(aHairlineColor));
    1184          12 :                 mpOutputDevice->SetFillColor();
    1185             : 
    1186          12 :                 if(0.0 == rStrokeAttribute.getFullDotDashLen())
    1187             :                 {
    1188             :                     // no line dashing, just copy
    1189           6 :                     aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon());
    1190             :                 }
    1191             :                 else
    1192             :                 {
    1193             :                     // else apply LineStyle
    1194           6 :                     basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(),
    1195           6 :                         rStrokeAttribute.getDotDashArray(),
    1196          12 :                         &aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen());
    1197             :                 }
    1198             : 
    1199          12 :                 const sal_uInt32 nCount(aHairlinePolyPolygon.count());
    1200             : 
    1201          12 :                 if(nCount)
    1202             :                 {
    1203          12 :                     const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing());
    1204          12 :                     aHairlinePolyPolygon.transform(maCurrentTransformation);
    1205             : 
    1206          12 :                     if(bAntiAliased)
    1207             :                     {
    1208           0 :                         if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0))
    1209             :                         {
    1210             :                             // line in range ]0.0 .. 1.0[
    1211             :                             // paint as simple hairline
    1212           0 :                             for(sal_uInt32 a(0); a < nCount; a++)
    1213             :                             {
    1214           0 :                                 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0);
    1215             :                             }
    1216             : 
    1217           0 :                             bDone = true;
    1218             :                         }
    1219           0 :                         else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0))
    1220             :                         {
    1221             :                             // line in range [1.0 .. 2.0[
    1222             :                             // paint as 2x2 with dynamic line distance
    1223           0 :                             basegfx::B2DHomMatrix aMat;
    1224           0 :                             const double fDistance(fDiscreteLineWidth - 1.0);
    1225           0 :                             const double fHalfDistance(fDistance * 0.5);
    1226             : 
    1227           0 :                             for(sal_uInt32 a(0); a < nCount; a++)
    1228             :                             {
    1229           0 :                                 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a));
    1230             : 
    1231           0 :                                 aMat.set(0, 2, -fHalfDistance);
    1232           0 :                                 aMat.set(1, 2, -fHalfDistance);
    1233           0 :                                 aCandidate.transform(aMat);
    1234           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1235             : 
    1236           0 :                                 aMat.set(0, 2, fDistance);
    1237           0 :                                 aMat.set(1, 2, 0.0);
    1238           0 :                                 aCandidate.transform(aMat);
    1239           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1240             : 
    1241           0 :                                 aMat.set(0, 2, 0.0);
    1242           0 :                                 aMat.set(1, 2, fDistance);
    1243           0 :                                 aCandidate.transform(aMat);
    1244           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1245             : 
    1246           0 :                                 aMat.set(0, 2, -fDistance);
    1247           0 :                                 aMat.set(1, 2, 0.0);
    1248           0 :                                 aCandidate.transform(aMat);
    1249           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1250           0 :                             }
    1251             : 
    1252           0 :                             bDone = true;
    1253             :                         }
    1254           0 :                         else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0))
    1255             :                         {
    1256             :                             // line in range [2.0 .. 3.0]
    1257             :                             // paint as cross in a 3x3  with dynamic line distance
    1258           0 :                             basegfx::B2DHomMatrix aMat;
    1259           0 :                             const double fDistance((fDiscreteLineWidth - 1.0) * 0.5);
    1260             : 
    1261           0 :                             for(sal_uInt32 a(0); a < nCount; a++)
    1262             :                             {
    1263           0 :                                 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a));
    1264             : 
    1265           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1266             : 
    1267           0 :                                 aMat.set(0, 2, -fDistance);
    1268           0 :                                 aMat.set(1, 2, 0.0);
    1269           0 :                                 aCandidate.transform(aMat);
    1270           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1271             : 
    1272           0 :                                 aMat.set(0, 2, fDistance);
    1273           0 :                                 aMat.set(1, 2, -fDistance);
    1274           0 :                                 aCandidate.transform(aMat);
    1275           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1276             : 
    1277           0 :                                 aMat.set(0, 2, fDistance);
    1278           0 :                                 aMat.set(1, 2, fDistance);
    1279           0 :                                 aCandidate.transform(aMat);
    1280           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1281             : 
    1282           0 :                                 aMat.set(0, 2, -fDistance);
    1283           0 :                                 aMat.set(1, 2, fDistance);
    1284           0 :                                 aCandidate.transform(aMat);
    1285           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1286           0 :                             }
    1287             : 
    1288           0 :                             bDone = true;
    1289             :                         }
    1290             :                         else
    1291             :                         {
    1292             :                             // #i101491# line width above 3.0
    1293             :                         }
    1294             :                     }
    1295             :                     else
    1296             :                     {
    1297          12 :                         if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5))
    1298             :                         {
    1299             :                             // line width below 1.5, draw the basic hairline polygon
    1300         482 :                             for(sal_uInt32 a(0); a < nCount; a++)
    1301             :                             {
    1302         470 :                                 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0);
    1303             :                             }
    1304             : 
    1305          12 :                             bDone = true;
    1306             :                         }
    1307           0 :                         else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5))
    1308             :                         {
    1309             :                             // line width is in range ]1.5 .. 2.5], use four hairlines
    1310             :                             // drawn in a square
    1311           0 :                             for(sal_uInt32 a(0); a < nCount; a++)
    1312             :                             {
    1313           0 :                                 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a));
    1314           0 :                                 basegfx::B2DHomMatrix aMat;
    1315             : 
    1316           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1317             : 
    1318           0 :                                 aMat.set(0, 2, 1.0);
    1319           0 :                                 aMat.set(1, 2, 0.0);
    1320           0 :                                 aCandidate.transform(aMat);
    1321             : 
    1322           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1323             : 
    1324           0 :                                 aMat.set(0, 2, 0.0);
    1325           0 :                                 aMat.set(1, 2, 1.0);
    1326           0 :                                 aCandidate.transform(aMat);
    1327             : 
    1328           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1329             : 
    1330           0 :                                 aMat.set(0, 2, -1.0);
    1331           0 :                                 aMat.set(1, 2, 0.0);
    1332           0 :                                 aCandidate.transform(aMat);
    1333             : 
    1334           0 :                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
    1335           0 :                             }
    1336             : 
    1337           0 :                             bDone = true;
    1338             :                         }
    1339             :                         else
    1340             :                         {
    1341             :                             // #i101491# line width is above 2.5
    1342             :                         }
    1343             :                     }
    1344             : 
    1345          12 :                     if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000)
    1346             :                     {
    1347             :                         // #i101491# If the polygon complexity uses more than a given amount, do
    1348             :                         // use OuputDevice::DrawPolyLine directly; this will avoid buffering all
    1349             :                         // decompositions in primtives (memory) and fallback to old line painting
    1350             :                         // for very complex polygons, too
    1351           0 :                         for(sal_uInt32 a(0); a < nCount; a++)
    1352             :                         {
    1353             :                             mpOutputDevice->DrawPolyLine(
    1354             :                                 aHairlinePolyPolygon.getB2DPolygon(a),
    1355             :                                 fDiscreteLineWidth,
    1356             :                                 rLineAttribute.getLineJoin(),
    1357           0 :                                 rLineAttribute.getLineCap());
    1358             :                         }
    1359             : 
    1360           0 :                         bDone = true;
    1361             :                     }
    1362          12 :                 }
    1363             :             }
    1364             : 
    1365          30 :             if(!bDone)
    1366             :             {
    1367             :                 // remeber that we enter a PolygonStrokePrimitive2D decomposition,
    1368             :                 // used for AA thick line drawing
    1369          18 :                 mnPolygonStrokePrimitive2D++;
    1370             : 
    1371             :                 // line width is big enough for standard filled polygon visualisation or zero
    1372          18 :                 process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D()));
    1373             : 
    1374             :                 // leave PolygonStrokePrimitive2D
    1375          18 :                 mnPolygonStrokePrimitive2D--;
    1376             :             }
    1377          30 :         }
    1378             : 
    1379           0 :         void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEpsPrimitive2D)
    1380             :         {
    1381             :             // The new decomposition of Metafiles made it necessary to add an Eps
    1382             :             // primitive to handle embedded Eps data. On some devices, this can be
    1383             :             // painted directly (mac, printer).
    1384             :             // To be able to handle the replacement correctly, i need to handle it myself
    1385             :             // since DrawEPS will not be able e.g. to rotate the replacement. To be able
    1386             :             // to do that, i added a boolean return to OutputDevice::DrawEPS(..)
    1387             :             // to know when EPS was handled directly already.
    1388           0 :             basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
    1389           0 :             aRange.transform(maCurrentTransformation * rEpsPrimitive2D.getEpsTransform());
    1390             : 
    1391           0 :             if(!aRange.isEmpty())
    1392             :             {
    1393             :                 const Rectangle aRectangle(
    1394           0 :                     (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
    1395           0 :                     (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
    1396             : 
    1397           0 :                 if(!aRectangle.IsEmpty())
    1398             :                 {
    1399             :                     // try to paint EPS directly without fallback visualisation
    1400             :                     const bool bEPSPaintedDirectly(mpOutputDevice->DrawEPS(
    1401             :                         aRectangle.TopLeft(),
    1402             :                         aRectangle.GetSize(),
    1403           0 :                         rEpsPrimitive2D.getGfxLink(),
    1404           0 :                         0));
    1405             : 
    1406           0 :                     if(!bEPSPaintedDirectly)
    1407             :                     {
    1408             :                         // use the decomposition which will correctly handle the
    1409             :                         // fallback visualisation using full transformation (e.g. rotation)
    1410           0 :                         process(rEpsPrimitive2D.get2DDecomposition(getViewInformation2D()));
    1411             :                     }
    1412             :                 }
    1413             :             }
    1414           0 :         }
    1415             : 
    1416           0 :         void VclProcessor2D::RenderSvgLinearAtomPrimitive2D(const primitive2d::SvgLinearAtomPrimitive2D& rCandidate)
    1417             :         {
    1418           0 :             const double fDelta(rCandidate.getOffsetB() - rCandidate.getOffsetA());
    1419             : 
    1420           0 :             if(basegfx::fTools::more(fDelta, 0.0))
    1421             :             {
    1422           0 :                 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA()));
    1423           0 :                 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB()));
    1424           0 :                 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
    1425             : 
    1426             :                 // use color distance and discrete lengths to calculate step count
    1427           0 :                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDelta, fDiscreteUnit));
    1428             : 
    1429             :                 // prepare loop and polygon
    1430           0 :                 double fStart(0.0);
    1431           0 :                 double fStep(fDelta / nSteps);
    1432             :                 const basegfx::B2DPolygon aPolygon(
    1433             :                     basegfx::tools::createPolygonFromRect(
    1434             :                         basegfx::B2DRange(
    1435           0 :                             rCandidate.getOffsetA() - fDiscreteUnit,
    1436             :                             0.0,
    1437           0 :                             rCandidate.getOffsetA() + fStep + fDiscreteUnit,
    1438           0 :                             1.0)));
    1439             : 
    1440             :                 // switch off line painting
    1441           0 :                 mpOutputDevice->SetLineColor();
    1442             : 
    1443             :                 // loop and paint
    1444           0 :                 for(sal_uInt32 a(0); a < nSteps; a++, fStart += fStep)
    1445             :                 {
    1446           0 :                     basegfx::B2DPolygon aNew(aPolygon);
    1447             : 
    1448           0 :                     aNew.transform(maCurrentTransformation * basegfx::tools::createTranslateB2DHomMatrix(fStart, 0.0));
    1449           0 :                     mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorA, aColorB, fStart/fDelta)));
    1450           0 :                     mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew));
    1451           0 :                 }
    1452             :             }
    1453           0 :         }
    1454             : 
    1455           0 :         void VclProcessor2D::RenderSvgRadialAtomPrimitive2D(const primitive2d::SvgRadialAtomPrimitive2D& rCandidate)
    1456             :         {
    1457           0 :             const double fDeltaScale(rCandidate.getScaleB() - rCandidate.getScaleA());
    1458             : 
    1459           0 :             if(basegfx::fTools::more(fDeltaScale, 0.0))
    1460             :             {
    1461           0 :                 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA()));
    1462           0 :                 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB()));
    1463           0 :                 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
    1464             : 
    1465             :                 // use color distance and discrete lengths to calculate step count
    1466           0 :                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDeltaScale, fDiscreteUnit));
    1467             : 
    1468             :                 // switch off line painting
    1469           0 :                 mpOutputDevice->SetLineColor();
    1470             : 
    1471             :                 // prepare loop (outside to inside)
    1472           0 :                 double fEndScale(rCandidate.getScaleB());
    1473           0 :                 double fStepScale(fDeltaScale / nSteps);
    1474             : 
    1475           0 :                 for(sal_uInt32 a(0); a < nSteps; a++, fEndScale -= fStepScale)
    1476             :                 {
    1477           0 :                     const double fUnitScale(fEndScale/fDeltaScale);
    1478           0 :                     basegfx::B2DHomMatrix aTransform;
    1479             : 
    1480           0 :                     if(rCandidate.isTranslateSet())
    1481             :                     {
    1482             :                         const basegfx::B2DVector aTranslate(
    1483             :                             basegfx::interpolate(
    1484             :                                 rCandidate.getTranslateA(),
    1485             :                                 rCandidate.getTranslateB(),
    1486           0 :                                 fUnitScale));
    1487             : 
    1488             :                         aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
    1489             :                             fEndScale,
    1490             :                             fEndScale,
    1491             :                             aTranslate.getX(),
    1492           0 :                             aTranslate.getY());
    1493             :                     }
    1494             :                     else
    1495             :                     {
    1496             :                         aTransform = basegfx::tools::createScaleB2DHomMatrix(
    1497             :                             fEndScale,
    1498           0 :                             fEndScale);
    1499             :                     }
    1500             : 
    1501           0 :                     basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle());
    1502             : 
    1503           0 :                     aNew.transform(maCurrentTransformation * aTransform);
    1504           0 :                     mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorA, aColorB, fUnitScale)));
    1505           0 :                     mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew));
    1506           0 :                 }
    1507             :             }
    1508           0 :         }
    1509             : 
    1510          30 :         void VclProcessor2D::adaptLineToFillDrawMode() const
    1511             :         {
    1512          30 :             const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
    1513             : 
    1514          30 :             if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE))
    1515             :             {
    1516           0 :                 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
    1517             : 
    1518           0 :                 if(nOriginalDrawMode & DRAWMODE_BLACKLINE)
    1519             :                 {
    1520           0 :                     nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
    1521             :                 }
    1522             :                 else
    1523             :                 {
    1524           0 :                     nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
    1525             :                 }
    1526             : 
    1527           0 :                 if(nOriginalDrawMode & DRAWMODE_GRAYLINE)
    1528             :                 {
    1529           0 :                     nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
    1530             :                 }
    1531             :                 else
    1532             :                 {
    1533           0 :                     nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
    1534             :                 }
    1535             : 
    1536           0 :                 if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE)
    1537             :                 {
    1538           0 :                     nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
    1539             :                 }
    1540             :                 else
    1541             :                 {
    1542           0 :                     nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
    1543             :                 }
    1544             : 
    1545           0 :                 if(nOriginalDrawMode & DRAWMODE_WHITELINE)
    1546             :                 {
    1547           0 :                     nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
    1548             :                 }
    1549             :                 else
    1550             :                 {
    1551           0 :                     nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
    1552             :                 }
    1553             : 
    1554           0 :                 if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE)
    1555             :                 {
    1556           0 :                     nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
    1557             :                 }
    1558             :                 else
    1559             :                 {
    1560           0 :                     nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
    1561             :                 }
    1562             : 
    1563           0 :                 mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
    1564             :             }
    1565          30 :         }
    1566             : 
    1567           7 :         void VclProcessor2D::adaptTextToFillDrawMode() const
    1568             :         {
    1569           7 :             const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
    1570           7 :             if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT))
    1571             :             {
    1572           0 :                 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
    1573             : 
    1574           0 :                 if(nOriginalDrawMode & DRAWMODE_BLACKTEXT)
    1575             :                 {
    1576           0 :                     nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
    1577             :                 }
    1578             :                 else
    1579             :                 {
    1580           0 :                     nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
    1581             :                 }
    1582             : 
    1583           0 :                 if(nOriginalDrawMode & DRAWMODE_GRAYTEXT)
    1584             :                 {
    1585           0 :                     nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
    1586             :                 }
    1587             :                 else
    1588             :                 {
    1589           0 :                     nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
    1590             :                 }
    1591             : 
    1592           0 :                 if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT)
    1593             :                 {
    1594           0 :                     nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
    1595             :                 }
    1596             :                 else
    1597             :                 {
    1598           0 :                     nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
    1599             :                 }
    1600             : 
    1601           0 :                 if(nOriginalDrawMode & DRAWMODE_WHITETEXT)
    1602             :                 {
    1603           0 :                     nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
    1604             :                 }
    1605             :                 else
    1606             :                 {
    1607           0 :                     nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
    1608             :                 }
    1609             : 
    1610           0 :                 if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT)
    1611             :                 {
    1612           0 :                     nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
    1613             :                 }
    1614             :                 else
    1615             :                 {
    1616           0 :                     nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
    1617             :                 }
    1618             : 
    1619           0 :                 mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
    1620             :             }
    1621           7 :         }
    1622             : 
    1623             :         //////////////////////////////////////////////////////////////////////////////
    1624             :         // process support
    1625             : 
    1626        1386 :         VclProcessor2D::VclProcessor2D(
    1627             :             const geometry::ViewInformation2D& rViewInformation,
    1628             :             OutputDevice& rOutDev)
    1629             :         :   BaseProcessor2D(rViewInformation),
    1630             :             mpOutputDevice(&rOutDev),
    1631             :             maBColorModifierStack(),
    1632             :             maCurrentTransformation(),
    1633             :             maDrawinglayerOpt(),
    1634        1386 :             mnPolygonStrokePrimitive2D(0)
    1635             :         {
    1636             :             // set digit language, derived from SvtCTLOptions to have the correct
    1637             :             // number display for arabic/hindi numerals
    1638        1386 :             rOutDev.SetDigitLanguage(drawinglayer::detail::getDigitLanguage());
    1639        1386 :         }
    1640             : 
    1641        1386 :         VclProcessor2D::~VclProcessor2D()
    1642             :         {
    1643        1386 :         }
    1644             :     } // end of namespace processor2d
    1645             : } // end of namespace drawinglayer
    1646             : 
    1647             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10