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

Generated by: LCOV version 1.10