LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/gdi - print2.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 554 0.0 %
Date: 2012-12-27 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <functional>
      21             : #include <algorithm>
      22             : #include <utility>
      23             : #include <list>
      24             : #include <vector>
      25             : 
      26             : #include <basegfx/polygon/b2dpolygon.hxx>
      27             : #include <basegfx/polygon/b2dpolygontools.hxx>
      28             : 
      29             : #include <tools/debug.hxx>
      30             : 
      31             : #include <vcl/virdev.hxx>
      32             : #include <vcl/metaact.hxx>
      33             : #include <vcl/gdimtf.hxx>
      34             : #include <vcl/print.hxx>
      35             : #include <vcl/svapp.hxx>
      36             : #include <vcl/bmpacc.hxx>
      37             : 
      38             : #include <print.h>
      39             : 
      40             : #include "pdfwriter_impl.hxx"
      41             : 
      42             : // -----------
      43             : // - Defines -
      44             : // -----------
      45             : 
      46             : #define MAX_TILE_WIDTH  1024
      47             : #define MAX_TILE_HEIGHT 1024
      48             : 
      49             : // ---------
      50             : // - Types -
      51             : // ---------
      52             : 
      53             : typedef ::std::pair< MetaAction*, int > Component; // MetaAction plus index in metafile
      54             : 
      55             : typedef ::std::list< Component > ComponentList;
      56             : 
      57             : // List of (intersecting) actions, plus overall bounds
      58           0 : struct ConnectedComponents
      59             : {
      60           0 :     ConnectedComponents() :
      61             :         aComponentList(),
      62             :         aBounds(),
      63             :         aBgColor(COL_WHITE),
      64             :         bIsSpecial(false),
      65           0 :         bIsFullyTransparent(false)
      66           0 :     {}
      67             : 
      68             :     ComponentList   aComponentList;
      69             :     Rectangle       aBounds;
      70             :     Color           aBgColor;
      71             :     bool            bIsSpecial;
      72             :     bool            bIsFullyTransparent;
      73             : };
      74             : 
      75             : typedef ::std::list< ConnectedComponents > ConnectedComponentsList;
      76             : 
      77             : 
      78             : // -----------
      79             : // - Printer -
      80             : // -----------
      81             : 
      82             : /** #i10613# Extracted from Printer::GetPreparedMetaFile. Returns true
      83             :     if given action requires special handling (usually because of
      84             :     transparency)
      85             : */
      86           0 : static bool ImplIsActionSpecial( const MetaAction& rAct )
      87             : {
      88           0 :     switch( rAct.GetType() )
      89             :     {
      90             :         case META_TRANSPARENT_ACTION:
      91           0 :             return true;
      92             : 
      93             :         case META_FLOATTRANSPARENT_ACTION:
      94           0 :             return true;
      95             : 
      96             :         case META_BMPEX_ACTION:
      97           0 :             return static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().IsTransparent();
      98             : 
      99             :         case META_BMPEXSCALE_ACTION:
     100           0 :             return static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx().IsTransparent();
     101             : 
     102             :         case META_BMPEXSCALEPART_ACTION:
     103           0 :             return static_cast<const MetaBmpExScalePartAction&>(rAct).GetBitmapEx().IsTransparent();
     104             : 
     105             :         default:
     106           0 :             return false;
     107             :     }
     108             : }
     109             : 
     110             : /** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
     111             :     yes, return true and update o_rBgColor
     112             :  */
     113           0 : static bool checkRect( Rectangle&       io_rPrevRect,
     114             :                        Color&           o_rBgColor,
     115             :                        const Rectangle& rCurrRect,
     116             :                        OutputDevice&    rMapModeVDev )
     117             : {
     118             :     // shape needs to fully cover previous content, and have uniform
     119             :     // color
     120             :     const bool bRet(
     121           0 :         rMapModeVDev.LogicToPixel(rCurrRect).IsInside(io_rPrevRect) &&
     122           0 :         rMapModeVDev.IsFillColor() );
     123             : 
     124           0 :     if( bRet )
     125             :     {
     126           0 :         io_rPrevRect = rCurrRect;
     127           0 :         o_rBgColor = rMapModeVDev.GetFillColor();
     128             :     }
     129             : 
     130           0 :     return bRet;
     131             : }
     132             : 
     133             : /** #107169# Convert BitmapEx to Bitmap with appropriately blended
     134             :     color. Convert MetaTransparentAction to plain polygon,
     135             :     appropriately colored
     136             : 
     137             :     @param o_rMtf
     138             :     Add converted actions to this metafile
     139             : */
     140           0 : static void ImplConvertTransparentAction( GDIMetaFile&        o_rMtf,
     141             :                                           const MetaAction&   rAct,
     142             :                                           const OutputDevice& rStateOutDev,
     143             :                                           Color               aBgColor )
     144             : {
     145           0 :     if( rAct.GetType() == META_TRANSPARENT_ACTION )
     146             :     {
     147           0 :         const MetaTransparentAction* pTransAct = static_cast<const MetaTransparentAction*>(&rAct);
     148           0 :         sal_uInt16                       nTransparency( pTransAct->GetTransparence() );
     149             : 
     150             :         // #i10613# Respect transparency for draw color
     151           0 :         if( nTransparency )
     152             :         {
     153           0 :             o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR|PUSH_FILLCOLOR ) );
     154             : 
     155             :             // assume white background for alpha blending
     156           0 :             Color aLineColor( rStateOutDev.GetLineColor() );
     157           0 :             aLineColor.SetRed( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetRed()) / 100L ) );
     158           0 :             aLineColor.SetGreen( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetGreen()) / 100L ) );
     159           0 :             aLineColor.SetBlue( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetBlue()) / 100L ) );
     160           0 :             o_rMtf.AddAction( new MetaLineColorAction(aLineColor, sal_True) );
     161             : 
     162           0 :             Color aFillColor( rStateOutDev.GetFillColor() );
     163           0 :             aFillColor.SetRed( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetRed()) / 100L ) );
     164           0 :             aFillColor.SetGreen( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetGreen()) / 100L ) );
     165           0 :             aFillColor.SetBlue( static_cast<sal_uInt8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetBlue()) / 100L ) );
     166           0 :             o_rMtf.AddAction( new MetaFillColorAction(aFillColor, sal_True) );
     167             :         }
     168             : 
     169           0 :         o_rMtf.AddAction( new MetaPolyPolygonAction(pTransAct->GetPolyPolygon()) );
     170             : 
     171           0 :         if( nTransparency )
     172           0 :             o_rMtf.AddAction( new MetaPopAction() );
     173             :     }
     174             :     else
     175             :     {
     176           0 :         BitmapEx aBmpEx;
     177             : 
     178           0 :         switch( rAct.GetType() )
     179             :         {
     180             :             case META_BMPEX_ACTION:
     181           0 :                 aBmpEx = static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx();
     182           0 :                 break;
     183             : 
     184             :             case META_BMPEXSCALE_ACTION:
     185           0 :                 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
     186           0 :                 break;
     187             : 
     188             :             case META_BMPEXSCALEPART_ACTION:
     189           0 :                 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
     190           0 :                 break;
     191             : 
     192             :             case META_TRANSPARENT_ACTION:
     193             : 
     194             :             default:
     195             :                 OSL_FAIL("Printer::GetPreparedMetafile impossible state reached");
     196           0 :                 break;
     197             :         }
     198             : 
     199           0 :         Bitmap aBmp( aBmpEx.GetBitmap() );
     200           0 :         if( !aBmpEx.IsAlpha() )
     201             :         {
     202             :             // blend with mask
     203           0 :             BitmapReadAccess* pRA = aBmp.AcquireReadAccess();
     204             : 
     205           0 :             if( !pRA )
     206           0 :                 return; // what else should I do?
     207             : 
     208           0 :             Color aActualColor( aBgColor );
     209             : 
     210           0 :             if( pRA->HasPalette() )
     211           0 :                 aActualColor = pRA->GetBestPaletteColor( aBgColor ).operator Color();
     212             : 
     213           0 :             aBmp.ReleaseAccess(pRA);
     214             : 
     215             :             // did we get true white?
     216           0 :             if( aActualColor.GetColorError( aBgColor ) )
     217             :             {
     218             :                 // no, create truecolor bitmap, then
     219           0 :                 aBmp.Convert( BMP_CONVERSION_24BIT );
     220             : 
     221             :                 // fill masked out areas white
     222           0 :                 aBmp.Replace( aBmpEx.GetMask(), aBgColor );
     223             :             }
     224             :             else
     225             :             {
     226             :                 // fill masked out areas white
     227           0 :                 aBmp.Replace( aBmpEx.GetMask(), aActualColor );
     228             :             }
     229             :         }
     230             :         else
     231             :         {
     232             :             // blend with alpha channel
     233           0 :             aBmp.Convert( BMP_CONVERSION_24BIT );
     234           0 :             aBmp.Blend(aBmpEx.GetAlpha(),aBgColor);
     235             :         }
     236             : 
     237             :         // add corresponding action
     238           0 :         switch( rAct.GetType() )
     239             :         {
     240             :             case META_BMPEX_ACTION:
     241             :                 o_rMtf.AddAction( new MetaBmpAction(
     242             :                                        static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
     243           0 :                                        aBmp ));
     244           0 :                 break;
     245             :             case META_BMPEXSCALE_ACTION:
     246             :                 o_rMtf.AddAction( new MetaBmpScaleAction(
     247             :                                        static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
     248             :                                        static_cast<const MetaBmpExScaleAction&>(rAct).GetSize(),
     249           0 :                                        aBmp ));
     250           0 :                 break;
     251             :             case META_BMPEXSCALEPART_ACTION:
     252             :                 o_rMtf.AddAction( new MetaBmpScalePartAction(
     253             :                                        static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
     254             :                                        static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize(),
     255             :                                        static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcPoint(),
     256             :                                        static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcSize(),
     257           0 :                                        aBmp ));
     258           0 :                 break;
     259             :             default:
     260             :                 OSL_FAIL("Unexpected case");
     261           0 :                 break;
     262           0 :         }
     263             :     }
     264             : }
     265             : 
     266             : // #i10613# Extracted from ImplCheckRect::ImplCreate
     267             : // Returns true, if given action creates visible (i.e. non-transparent) output
     268           0 : static bool ImplIsNotTransparent( const MetaAction& rAct, const OutputDevice& rOut )
     269             : {
     270           0 :     const bool  bLineTransparency( rOut.IsLineColor() ? rOut.GetLineColor().GetTransparency() == 255 : true );
     271           0 :     const bool  bFillTransparency( rOut.IsFillColor() ? rOut.GetFillColor().GetTransparency() == 255 : true );
     272           0 :     bool        bRet( false );
     273             : 
     274           0 :     switch( rAct.GetType() )
     275             :     {
     276             :         case META_POINT_ACTION:
     277           0 :             if( !bLineTransparency )
     278           0 :                 bRet = true;
     279           0 :             break;
     280             : 
     281             :         case META_LINE_ACTION:
     282           0 :             if( !bLineTransparency )
     283           0 :                 bRet = true;
     284           0 :             break;
     285             : 
     286             :         case META_RECT_ACTION:
     287           0 :             if( !bLineTransparency || !bFillTransparency )
     288           0 :                 bRet = true;
     289           0 :             break;
     290             : 
     291             :         case META_ROUNDRECT_ACTION:
     292           0 :             if( !bLineTransparency || !bFillTransparency )
     293           0 :                 bRet = true;
     294           0 :             break;
     295             : 
     296             :         case META_ELLIPSE_ACTION:
     297           0 :             if( !bLineTransparency || !bFillTransparency )
     298           0 :                 bRet = true;
     299           0 :             break;
     300             : 
     301             :         case META_ARC_ACTION:
     302           0 :             if( !bLineTransparency || !bFillTransparency )
     303           0 :                 bRet = true;
     304           0 :             break;
     305             : 
     306             :         case META_PIE_ACTION:
     307           0 :             if( !bLineTransparency || !bFillTransparency )
     308           0 :                 bRet = true;
     309           0 :             break;
     310             : 
     311             :         case META_CHORD_ACTION:
     312           0 :             if( !bLineTransparency || !bFillTransparency )
     313           0 :                 bRet = true;
     314           0 :             break;
     315             : 
     316             :         case META_POLYLINE_ACTION:
     317           0 :             if( !bLineTransparency )
     318           0 :                 bRet = true;
     319           0 :             break;
     320             : 
     321             :         case META_POLYGON_ACTION:
     322           0 :             if( !bLineTransparency || !bFillTransparency )
     323           0 :                 bRet = true;
     324           0 :             break;
     325             : 
     326             :         case META_POLYPOLYGON_ACTION:
     327           0 :             if( !bLineTransparency || !bFillTransparency )
     328           0 :                 bRet = true;
     329           0 :             break;
     330             : 
     331             :         case META_TEXT_ACTION:
     332             :         {
     333           0 :             const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
     334           0 :             const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
     335             : 
     336           0 :             if( aString.Len() )
     337           0 :                 bRet = true;
     338             :         }
     339           0 :         break;
     340             : 
     341             :         case META_TEXTARRAY_ACTION:
     342             :         {
     343           0 :             const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
     344           0 :             const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
     345             : 
     346           0 :             if( aString.Len() )
     347           0 :                 bRet = true;
     348             :         }
     349           0 :         break;
     350             : 
     351             :         case META_PIXEL_ACTION:
     352             :         case META_BMP_ACTION:
     353             :         case META_BMPSCALE_ACTION:
     354             :         case META_BMPSCALEPART_ACTION:
     355             :         case META_BMPEX_ACTION:
     356             :         case META_BMPEXSCALE_ACTION:
     357             :         case META_BMPEXSCALEPART_ACTION:
     358             :         case META_MASK_ACTION:
     359             :         case META_MASKSCALE_ACTION:
     360             :         case META_MASKSCALEPART_ACTION:
     361             :         case META_GRADIENT_ACTION:
     362             :         case META_GRADIENTEX_ACTION:
     363             :         case META_HATCH_ACTION:
     364             :         case META_WALLPAPER_ACTION:
     365             :         case META_TRANSPARENT_ACTION:
     366             :         case META_FLOATTRANSPARENT_ACTION:
     367             :         case META_EPS_ACTION:
     368             :         case META_TEXTRECT_ACTION:
     369             :         case META_STRETCHTEXT_ACTION:
     370             :         case META_TEXTLINE_ACTION:
     371             :             // all other actions: generate non-transparent output
     372           0 :             bRet = true;
     373           0 :             break;
     374             : 
     375             :         default:
     376           0 :             break;
     377             :     }
     378             : 
     379           0 :     return bRet;
     380             : }
     381             : 
     382             : // #i10613# Extracted from ImplCheckRect::ImplCreate
     383           0 : static Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevice& rOut )
     384             : {
     385           0 :     Rectangle aActionBounds;
     386             : 
     387           0 :     switch( rAct.GetType() )
     388             :     {
     389             :         case META_PIXEL_ACTION:
     390           0 :             aActionBounds = Rectangle( static_cast<const MetaPixelAction&>(rAct).GetPoint(), Size( 1, 1 ) );
     391           0 :             break;
     392             : 
     393             :         case META_POINT_ACTION:
     394           0 :             aActionBounds = Rectangle( static_cast<const MetaPointAction&>(rAct).GetPoint(), Size( 1, 1 ) );
     395           0 :             break;
     396             : 
     397             :         case META_LINE_ACTION:
     398             :         {
     399           0 :             const MetaLineAction& rMetaLineAction = static_cast<const MetaLineAction&>(rAct);
     400           0 :             aActionBounds = Rectangle( rMetaLineAction.GetStartPoint(),  rMetaLineAction.GetEndPoint() );
     401           0 :             aActionBounds.Justify();
     402           0 :             const long nLineWidth(rMetaLineAction.GetLineInfo().GetWidth());
     403           0 :             if(nLineWidth)
     404             :             {
     405           0 :                 const long nHalfLineWidth((nLineWidth + 1) / 2);
     406           0 :                 aActionBounds.Left() -= nHalfLineWidth;
     407           0 :                 aActionBounds.Top() -= nHalfLineWidth;
     408           0 :                 aActionBounds.Right() += nHalfLineWidth;
     409           0 :                 aActionBounds.Bottom() += nHalfLineWidth;
     410             :             }
     411           0 :             break;
     412             :         }
     413             : 
     414             :         case META_RECT_ACTION:
     415           0 :             aActionBounds = static_cast<const MetaRectAction&>(rAct).GetRect();
     416           0 :             break;
     417             : 
     418             :         case META_ROUNDRECT_ACTION:
     419           0 :             aActionBounds = Polygon( static_cast<const MetaRoundRectAction&>(rAct).GetRect(),
     420             :                                      static_cast<const MetaRoundRectAction&>(rAct).GetHorzRound(),
     421           0 :                                      static_cast<const MetaRoundRectAction&>(rAct).GetVertRound() ).GetBoundRect();
     422           0 :             break;
     423             : 
     424             :         case META_ELLIPSE_ACTION:
     425             :         {
     426           0 :             const Rectangle& rRect = static_cast<const MetaEllipseAction&>(rAct).GetRect();
     427             :             aActionBounds = Polygon( rRect.Center(),
     428           0 :                                      rRect.GetWidth() >> 1,
     429           0 :                                      rRect.GetHeight() >> 1 ).GetBoundRect();
     430           0 :             break;
     431             :         }
     432             : 
     433             :         case META_ARC_ACTION:
     434           0 :             aActionBounds = Polygon( static_cast<const MetaArcAction&>(rAct).GetRect(),
     435           0 :                                      static_cast<const MetaArcAction&>(rAct).GetStartPoint(),
     436           0 :                                      static_cast<const MetaArcAction&>(rAct).GetEndPoint(), POLY_ARC ).GetBoundRect();
     437           0 :             break;
     438             : 
     439             :         case META_PIE_ACTION:
     440           0 :             aActionBounds = Polygon( static_cast<const MetaPieAction&>(rAct).GetRect(),
     441           0 :                                      static_cast<const MetaPieAction&>(rAct).GetStartPoint(),
     442           0 :                                      static_cast<const MetaPieAction&>(rAct).GetEndPoint(), POLY_PIE ).GetBoundRect();
     443           0 :             break;
     444             : 
     445             :         case META_CHORD_ACTION:
     446           0 :             aActionBounds = Polygon( static_cast<const MetaChordAction&>(rAct).GetRect(),
     447           0 :                                      static_cast<const MetaChordAction&>(rAct).GetStartPoint(),
     448           0 :                                      static_cast<const MetaChordAction&>(rAct).GetEndPoint(), POLY_CHORD ).GetBoundRect();
     449           0 :             break;
     450             : 
     451             :         case META_POLYLINE_ACTION:
     452             :         {
     453           0 :             const MetaPolyLineAction& rMetaPolyLineAction = static_cast<const MetaPolyLineAction&>(rAct);
     454           0 :             aActionBounds = rMetaPolyLineAction.GetPolygon().GetBoundRect();
     455           0 :             const long nLineWidth(rMetaPolyLineAction.GetLineInfo().GetWidth());
     456           0 :             if(nLineWidth)
     457             :             {
     458           0 :                 const long nHalfLineWidth((nLineWidth + 1) / 2);
     459           0 :                 aActionBounds.Left() -= nHalfLineWidth;
     460           0 :                 aActionBounds.Top() -= nHalfLineWidth;
     461           0 :                 aActionBounds.Right() += nHalfLineWidth;
     462           0 :                 aActionBounds.Bottom() += nHalfLineWidth;
     463             :             }
     464           0 :             break;
     465             :         }
     466             : 
     467             :         case META_POLYGON_ACTION:
     468           0 :             aActionBounds = static_cast<const MetaPolygonAction&>(rAct).GetPolygon().GetBoundRect();
     469           0 :             break;
     470             : 
     471             :         case META_POLYPOLYGON_ACTION:
     472           0 :             aActionBounds = static_cast<const MetaPolyPolygonAction&>(rAct).GetPolyPolygon().GetBoundRect();
     473           0 :             break;
     474             : 
     475             :         case META_BMP_ACTION:
     476           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpAction&>(rAct).GetPoint(),
     477           0 :                                        rOut.PixelToLogic( static_cast<const MetaBmpAction&>(rAct).GetBitmap().GetSizePixel() ) );
     478           0 :             break;
     479             : 
     480             :         case META_BMPSCALE_ACTION:
     481           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpScaleAction&>(rAct).GetPoint(),
     482           0 :                                        static_cast<const MetaBmpScaleAction&>(rAct).GetSize() );
     483           0 :             break;
     484             : 
     485             :         case META_BMPSCALEPART_ACTION:
     486           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpScalePartAction&>(rAct).GetDestPoint(),
     487           0 :                                        static_cast<const MetaBmpScalePartAction&>(rAct).GetDestSize() );
     488           0 :             break;
     489             : 
     490             :         case META_BMPEX_ACTION:
     491           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
     492           0 :                                        rOut.PixelToLogic( static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().GetSizePixel() ) );
     493           0 :             break;
     494             : 
     495             :         case META_BMPEXSCALE_ACTION:
     496           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
     497           0 :                                        static_cast<const MetaBmpExScaleAction&>(rAct).GetSize() );
     498           0 :             break;
     499             : 
     500             :         case META_BMPEXSCALEPART_ACTION:
     501           0 :             aActionBounds = Rectangle( static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
     502           0 :                                        static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize() );
     503           0 :             break;
     504             : 
     505             :         case META_MASK_ACTION:
     506           0 :             aActionBounds = Rectangle( static_cast<const MetaMaskAction&>(rAct).GetPoint(),
     507           0 :                                        rOut.PixelToLogic( static_cast<const MetaMaskAction&>(rAct).GetBitmap().GetSizePixel() ) );
     508           0 :             break;
     509             : 
     510             :         case META_MASKSCALE_ACTION:
     511           0 :             aActionBounds = Rectangle( static_cast<const MetaMaskScaleAction&>(rAct).GetPoint(),
     512           0 :                                        static_cast<const MetaMaskScaleAction&>(rAct).GetSize() );
     513           0 :             break;
     514             : 
     515             :         case META_MASKSCALEPART_ACTION:
     516           0 :             aActionBounds = Rectangle( static_cast<const MetaMaskScalePartAction&>(rAct).GetDestPoint(),
     517           0 :                                        static_cast<const MetaMaskScalePartAction&>(rAct).GetDestSize() );
     518           0 :             break;
     519             : 
     520             :         case META_GRADIENT_ACTION:
     521           0 :             aActionBounds = static_cast<const MetaGradientAction&>(rAct).GetRect();
     522           0 :             break;
     523             : 
     524             :         case META_GRADIENTEX_ACTION:
     525           0 :             aActionBounds = static_cast<const MetaGradientExAction&>(rAct).GetPolyPolygon().GetBoundRect();
     526           0 :             break;
     527             : 
     528             :         case META_HATCH_ACTION:
     529           0 :             aActionBounds = static_cast<const MetaHatchAction&>(rAct).GetPolyPolygon().GetBoundRect();
     530           0 :             break;
     531             : 
     532             :         case META_WALLPAPER_ACTION:
     533           0 :             aActionBounds = static_cast<const MetaWallpaperAction&>(rAct).GetRect();
     534           0 :             break;
     535             : 
     536             :         case META_TRANSPARENT_ACTION:
     537           0 :             aActionBounds = static_cast<const MetaTransparentAction&>(rAct).GetPolyPolygon().GetBoundRect();
     538           0 :             break;
     539             : 
     540             :         case META_FLOATTRANSPARENT_ACTION:
     541           0 :             aActionBounds = Rectangle( static_cast<const MetaFloatTransparentAction&>(rAct).GetPoint(),
     542           0 :                                        static_cast<const MetaFloatTransparentAction&>(rAct).GetSize() );
     543           0 :             break;
     544             : 
     545             :         case META_EPS_ACTION:
     546           0 :             aActionBounds = Rectangle( static_cast<const MetaEPSAction&>(rAct).GetPoint(),
     547           0 :                                        static_cast<const MetaEPSAction&>(rAct).GetSize() );
     548           0 :             break;
     549             : 
     550             :         case META_TEXT_ACTION:
     551             :         {
     552           0 :             const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
     553           0 :             const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
     554             : 
     555           0 :             if( aString.Len() )
     556             :             {
     557           0 :                 const Point aPtLog( rTextAct.GetPoint() );
     558             : 
     559             :                 // #105987# Use API method instead of Impl* methods
     560             :                 // #107490# Set base parameter equal to index parameter
     561           0 :                 rOut.GetTextBoundRect( aActionBounds, rTextAct.GetText(), rTextAct.GetIndex(),
     562           0 :                                        rTextAct.GetIndex(), rTextAct.GetLen() );
     563           0 :                 aActionBounds.Move( aPtLog.X(), aPtLog.Y() );
     564           0 :             }
     565             :         }
     566           0 :         break;
     567             : 
     568             :         case META_TEXTARRAY_ACTION:
     569             :         {
     570           0 :             const MetaTextArrayAction&  rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
     571           0 :             const XubString             aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
     572           0 :             const long                  nLen = aString.Len();
     573             : 
     574           0 :             if( nLen )
     575             :             {
     576             :                 // #105987# ImplLayout takes everything in logical coordinates
     577           0 :                 SalLayout* pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
     578           0 :                                                          rTextAct.GetLen(), rTextAct.GetPoint(),
     579           0 :                                                          0, rTextAct.GetDXArray() );
     580           0 :                 if( pSalLayout )
     581             :                 {
     582           0 :                     Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
     583           0 :                     aActionBounds = rOut.PixelToLogic( aBoundRect );
     584           0 :                     pSalLayout->Release();
     585             :                 }
     586           0 :             }
     587             :         }
     588           0 :         break;
     589             : 
     590             :         case META_TEXTRECT_ACTION:
     591           0 :             aActionBounds = static_cast<const MetaTextRectAction&>(rAct).GetRect();
     592           0 :             break;
     593             : 
     594             :         case META_STRETCHTEXT_ACTION:
     595             :         {
     596           0 :             const MetaStretchTextAction& rTextAct = static_cast<const MetaStretchTextAction&>(rAct);
     597           0 :             const XubString              aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
     598           0 :             const long                   nLen = aString.Len();
     599             : 
     600             :             // #i16195# Literate copy from TextArray action, the
     601             :             // semantics for the ImplLayout call are copied from the
     602             :             // OutDev::DrawStretchText() code. Unfortunately, also in
     603             :             // this case, public outdev methods such as GetTextWidth()
     604             :             // don't provide enough info.
     605           0 :             if( nLen )
     606             :             {
     607             :                 // #105987# ImplLayout takes everything in logical coordinates
     608           0 :                 SalLayout* pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
     609           0 :                                                          rTextAct.GetLen(), rTextAct.GetPoint(),
     610           0 :                                                          rTextAct.GetWidth() );
     611           0 :                 if( pSalLayout )
     612             :                 {
     613           0 :                     Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
     614           0 :                     aActionBounds = rOut.PixelToLogic( aBoundRect );
     615           0 :                     pSalLayout->Release();
     616             :                 }
     617           0 :             }
     618             :         }
     619           0 :         break;
     620             : 
     621             :         case META_TEXTLINE_ACTION:
     622             :             OSL_FAIL("META_TEXTLINE_ACTION not supported");
     623           0 :         break;
     624             : 
     625             :         default:
     626           0 :             break;
     627             :     }
     628             : 
     629           0 :     if( !aActionBounds.IsEmpty() )
     630           0 :         return rOut.LogicToPixel( aActionBounds );
     631             :     else
     632           0 :         return Rectangle();
     633             : }
     634             : 
     635           0 : static bool ImplIsActionHandlingTransparency( const MetaAction& rAct )
     636             : {
     637             :     // META_FLOATTRANSPARENT_ACTION can contain a whole metafile,
     638             :     // which is to be rendered with the given transparent gradient. We
     639             :     // currently cannot emulate transparent painting on a white
     640             :     // background reliably.
     641             : 
     642             :     // the remainder can handle printing itself correctly on a uniform
     643             :     // white background.
     644           0 :     switch( rAct.GetType() )
     645             :     {
     646             :         case META_TRANSPARENT_ACTION:
     647             :         case META_BMPEX_ACTION:
     648             :         case META_BMPEXSCALE_ACTION:
     649             :         case META_BMPEXSCALEPART_ACTION:
     650           0 :             return true;
     651             : 
     652             :         default:
     653           0 :             return false;
     654             :     }
     655             : }
     656             : 
     657             : // remove comment to enable highlighting of generated output
     658           0 : bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
     659             :                                                      long nMaxBmpDPIX, long nMaxBmpDPIY,
     660             :                                                      bool bReduceTransparency, bool bTransparencyAutoMode,
     661             :                                                      bool bDownsampleBitmaps,
     662             :                                                      const Color& rBackground
     663             :                                                      )
     664             : {
     665             :     MetaAction*             pCurrAct;
     666           0 :     bool                    bTransparent( false );
     667             : 
     668           0 :     rOutMtf.Clear();
     669             : 
     670           0 :     if( ! bReduceTransparency || bTransparencyAutoMode )
     671             :     {
     672             :         // watch for transparent drawing actions
     673           0 :         for( pCurrAct = ( (GDIMetaFile&) rInMtf ).FirstAction();
     674           0 :              pCurrAct && !bTransparent;
     675           0 :              pCurrAct = ( (GDIMetaFile&) rInMtf ).NextAction() )
     676             :         {
     677             :             // #i10613# Extracted "specialness" predicate into extra method
     678             : 
     679             :             // #107169# Also examine metafiles with masked bitmaps in
     680             :             // detail. Further down, this is optimized in such a way
     681             :             // that there's no unnecessary painting of masked bitmaps
     682             :             // (which are _always_ subdivided into rectangular regions
     683             :             // of uniform opacity): if a masked bitmap is printed over
     684             :             // empty background, we convert to a plain bitmap with
     685             :             // white background.
     686           0 :             if( ImplIsActionSpecial( *pCurrAct ) )
     687             :             {
     688           0 :                 bTransparent = true;
     689             :             }
     690             :         }
     691             :     }
     692             : 
     693             :     // #i10613# Determine set of connected components containing transparent objects. These are
     694             :     // then processed as bitmaps, the original actions are removed from the metafile.
     695           0 :     if( !bTransparent )
     696             :     {
     697             :         // nothing transparent -> just copy
     698           0 :         rOutMtf = rInMtf;
     699             :     }
     700             :     else
     701             :     {
     702             :         // #i10613#
     703             :         // This works as follows: we want a number of distinct sets of
     704             :         // connected components, where each set contains metafile
     705             :         // actions that are intersecting (note: there are possibly
     706             :         // more actions contained as are directly intersecting,
     707             :         // because we can only produce rectangular bitmaps later
     708             :         // on. Thus, each set of connected components is the smallest
     709             :         // enclosing, axis-aligned rectangle that completely bounds a
     710             :         // number of intersecting metafile actions, plus any action
     711             :         // that would otherwise be cut in two). Therefore, we
     712             :         // iteratively add metafile actions from the original metafile
     713             :         // to this connected components list (aCCList), by checking
     714             :         // each element's bounding box against intersection with the
     715             :         // metaaction at hand.
     716             :         // All those intersecting elements are removed from aCCList
     717             :         // and collected in a temporary list (aCCMergeList). After all
     718             :         // elements have been checked, the aCCMergeList elements are
     719             :         // merged with the metaaction at hand into one resulting
     720             :         // connected component, with one big bounding box, and
     721             :         // inserted into aCCList again.
     722             :         // The time complexity of this algorithm is O(n^3), where n is
     723             :         // the number of metafile actions, and it finds all distinct
     724             :         // regions of rectangle-bounded connected components. This
     725             :         // algorithm was designed by AF.
     726             :         //
     727             : 
     728             :         //
     729             :         //  STAGE 1: Detect background
     730             :         //  ==========================
     731             :         //
     732             : 
     733             :         // Receives uniform background content, and is _not_ merged
     734             :         // nor checked for intersection against other aCCList elements
     735           0 :         ConnectedComponents aBackgroundComponent;
     736             : 
     737             :         // create an OutputDevice to record mapmode changes and the like
     738           0 :         VirtualDevice aMapModeVDev;
     739           0 :         aMapModeVDev.mnDPIX = mnDPIX;
     740           0 :         aMapModeVDev.mnDPIY = mnDPIY;
     741           0 :         aMapModeVDev.EnableOutput(sal_False);
     742             : 
     743             :         int nLastBgAction, nActionNum;
     744             : 
     745             :         // weed out page-filling background objects (if they are
     746             :         // uniformly coloured). Keeping them outside the other
     747             :         // connected components often prevents whole-page bitmap
     748             :         // generation.
     749           0 :         bool bStillBackground=true; // true until first non-bg action
     750           0 :         nActionNum=0; nLastBgAction=-1;
     751           0 :         pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
     752           0 :         if( rBackground != Color( COL_TRANSPARENT ) )
     753             :         {
     754           0 :             aBackgroundComponent.aBgColor = rBackground;
     755           0 :             if( meOutDevType == OUTDEV_PRINTER )
     756             :             {
     757           0 :                 Printer* pThis = dynamic_cast<Printer*>(this);
     758           0 :                 Point aPageOffset = pThis->GetPageOffsetPixel();
     759           0 :                 aPageOffset = Point( 0, 0 ) - aPageOffset;
     760           0 :                 Size aSize  = pThis->GetPaperSizePixel();
     761           0 :                 aBackgroundComponent.aBounds = Rectangle( aPageOffset, aSize );
     762             :             }
     763             :             else
     764           0 :                 aBackgroundComponent.aBounds = Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
     765             :         }
     766           0 :         while( pCurrAct && bStillBackground )
     767             :         {
     768           0 :             switch( pCurrAct->GetType() )
     769             :             {
     770             :                 case META_RECT_ACTION:
     771             :                 {
     772           0 :                     if( !checkRect(
     773             :                             aBackgroundComponent.aBounds,
     774             :                             aBackgroundComponent.aBgColor,
     775           0 :                             static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
     776           0 :                             aMapModeVDev) )
     777           0 :                         bStillBackground=false; // incomplete occlusion of background
     778             :                     else
     779           0 :                         nLastBgAction=nActionNum; // this _is_ background
     780           0 :                     break;
     781             :                 }
     782             :                 case META_POLYGON_ACTION:
     783             :                 {
     784             :                     const Polygon aPoly(
     785           0 :                         static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
     786           0 :                     if( !basegfx::tools::isRectangle(
     787           0 :                             aPoly.getB2DPolygon()) ||
     788             :                         !checkRect(
     789             :                             aBackgroundComponent.aBounds,
     790             :                             aBackgroundComponent.aBgColor,
     791             :                             aPoly.GetBoundRect(),
     792           0 :                             aMapModeVDev) )
     793           0 :                         bStillBackground=false; // incomplete occlusion of background
     794             :                     else
     795           0 :                         nLastBgAction=nActionNum; // this _is_ background
     796           0 :                     break;
     797             :                 }
     798             :                 case META_POLYPOLYGON_ACTION:
     799             :                 {
     800             :                     const PolyPolygon aPoly(
     801           0 :                         static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
     802           0 :                     if( aPoly.Count() != 1 ||
     803             :                         !basegfx::tools::isRectangle(
     804           0 :                             aPoly[0].getB2DPolygon()) ||
     805             :                         !checkRect(
     806             :                             aBackgroundComponent.aBounds,
     807             :                             aBackgroundComponent.aBgColor,
     808             :                             aPoly.GetBoundRect(),
     809           0 :                             aMapModeVDev) )
     810           0 :                         bStillBackground=false; // incomplete occlusion of background
     811             :                     else
     812           0 :                         nLastBgAction=nActionNum; // this _is_ background
     813           0 :                     break;
     814             :                 }
     815             :                 case META_WALLPAPER_ACTION:
     816             :                 {
     817           0 :                     if( !checkRect(
     818             :                             aBackgroundComponent.aBounds,
     819             :                             aBackgroundComponent.aBgColor,
     820           0 :                             static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
     821           0 :                             aMapModeVDev) )
     822           0 :                         bStillBackground=false; // incomplete occlusion of background
     823             :                     else
     824           0 :                         nLastBgAction=nActionNum; // this _is_ background
     825           0 :                     break;
     826             :                 }
     827             :                 default:
     828             :                 {
     829           0 :                     if( ImplIsNotTransparent( *pCurrAct,
     830           0 :                                               aMapModeVDev ) )
     831           0 :                         bStillBackground=false; // non-transparent action, possibly
     832             :                                                 // not uniform
     833             :                     else
     834             :                         // extend current bounds (next uniform action
     835             :                         // needs to fully cover this area)
     836             :                         aBackgroundComponent.aBounds.Union(
     837           0 :                             ImplCalcActionBounds(*pCurrAct, aMapModeVDev) );
     838           0 :                     break;
     839             :                 }
     840             :             }
     841             : 
     842             :             // execute action to get correct MapModes etc.
     843           0 :             pCurrAct->Execute( &aMapModeVDev );
     844             : 
     845           0 :             pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
     846           0 :             ++nActionNum;
     847             :         }
     848             : 
     849             :         // clean up aMapModeVDev
     850           0 :         sal_uInt32 nCount = aMapModeVDev.GetGCStackDepth();
     851           0 :         while( nCount-- )
     852           0 :             aMapModeVDev.Pop();
     853             : 
     854           0 :         ConnectedComponentsList aCCList; // list containing distinct sets of connected components as elements.
     855             : 
     856             :         // fast-forward until one after the last background action
     857             :         // (need to reconstruct map mode vdev state)
     858           0 :         nActionNum=0;
     859           0 :         pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
     860           0 :         while( pCurrAct && nActionNum<=nLastBgAction )
     861             :         {
     862             :             // up to and including last ink-generating background
     863             :             // action go to background component
     864             :             aBackgroundComponent.aComponentList.push_back(
     865             :                 ::std::make_pair(
     866           0 :                     pCurrAct, nActionNum) );
     867             : 
     868             :             // execute action to get correct MapModes etc.
     869           0 :             pCurrAct->Execute( &aMapModeVDev );
     870           0 :             pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
     871           0 :             ++nActionNum;
     872             :         }
     873             : 
     874             :         //
     875             :         //  STAGE 2: Generate connected components list
     876             :         //  ===========================================
     877             :         //
     878             : 
     879             :         // iterate over all actions (start where background action
     880             :         // search left off)
     881           0 :         for( ;
     882             :              pCurrAct;
     883           0 :              pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
     884             :         {
     885             :             // execute action to get correct MapModes etc.
     886           0 :             pCurrAct->Execute( &aMapModeVDev );
     887             : 
     888             :             // cache bounds of current action
     889           0 :             const Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, aMapModeVDev) );
     890             : 
     891             :             // accumulate collected bounds here, initialize with current action
     892           0 :             Rectangle                               aTotalBounds( aBBCurrAct ); // thus,
     893             :                                                                                 // aTotalComponents.aBounds
     894             :                                                                                 // is
     895             :                                                                                 // empty
     896             :                                                                                 // for
     897             :                                                                                 // non-output-generating
     898             :                                                                                 // actions
     899           0 :             bool                                    bTreatSpecial( false );
     900           0 :             ConnectedComponents                     aTotalComponents;
     901             : 
     902             :             //
     903             :             //  STAGE 2.1: Search for intersecting cc entries
     904             :             //  =============================================
     905             :             //
     906             : 
     907             :             // if aBBCurrAct is empty, it will intersect with no
     908             :             // aCCList member. Thus, we can save the check.
     909             :             // Furthermore, this ensures that non-output-generating
     910             :             // actions get their own aCCList entry, which is necessary
     911             :             // when copying them to the output metafile (see stage 4
     912             :             // below).
     913             : 
     914             :             // #107169# Wholly transparent objects need
     915             :             // not be considered for connected components,
     916             :             // too. Just put each of them into a separate
     917             :             // component.
     918           0 :             aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, aMapModeVDev);
     919             : 
     920           0 :             if( !aBBCurrAct.IsEmpty() &&
     921           0 :                 !aTotalComponents.bIsFullyTransparent )
     922             :             {
     923           0 :                 if( !aBackgroundComponent.aComponentList.empty() &&
     924           0 :                     !aBackgroundComponent.aBounds.IsInside(aTotalBounds) )
     925             :                 {
     926             :                     // it seems the background is not large enough. to
     927             :                     // be on the safe side, combine with this component.
     928           0 :                     aTotalBounds.Union( aBackgroundComponent.aBounds );
     929             : 
     930             :                     // extract all aCurr actions to aTotalComponents
     931             :                     aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
     932           0 :                                                             aBackgroundComponent.aComponentList );
     933             : 
     934           0 :                     if( aBackgroundComponent.bIsSpecial )
     935           0 :                         bTreatSpecial = true;
     936             :                 }
     937             : 
     938           0 :                 ConnectedComponentsList::iterator       aCurrCC;
     939           0 :                 const ConnectedComponentsList::iterator aLastCC( aCCList.end() );
     940             :                 bool                                    bSomeComponentsChanged;
     941             : 
     942             :                 // now, this is unfortunate: since changing anyone of
     943             :                 // the aCCList elements (e.g. by merging or addition
     944             :                 // of an action) might generate new intersection with
     945             :                 // other aCCList elements, have to repeat the whole
     946             :                 // element scanning, until nothing changes anymore.
     947             :                 // Thus, this loop here makes us O(n^3) in the worst
     948             :                 // case.
     949           0 :                 do
     950             :                 {
     951             :                     // only loop here if 'intersects' branch below was hit
     952           0 :                     bSomeComponentsChanged = false;
     953             : 
     954             :                     // iterate over all current members of aCCList
     955           0 :                     for( aCurrCC=aCCList.begin(); aCurrCC != aLastCC; )
     956             :                     {
     957             :                         // first check if current element's bounds are
     958             :                         // empty. This ensures that empty actions are not
     959             :                         // merged into one component, as a matter of fact,
     960             :                         // they have no position.
     961             : 
     962             :                         // #107169# Wholly transparent objects need
     963             :                         // not be considered for connected components,
     964             :                         // too. Just put each of them into a separate
     965             :                         // component.
     966           0 :                         if( !aCurrCC->aBounds.IsEmpty() &&
     967           0 :                             !aCurrCC->bIsFullyTransparent &&
     968           0 :                             aCurrCC->aBounds.IsOver( aTotalBounds ) )
     969             :                         {
     970             :                             // union the intersecting aCCList element into aTotalComponents
     971             : 
     972             :                             // calc union bounding box
     973           0 :                             aTotalBounds.Union( aCurrCC->aBounds );
     974             : 
     975             :                             // extract all aCurr actions to aTotalComponents
     976             :                             aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
     977           0 :                                                                     aCurrCC->aComponentList );
     978             : 
     979           0 :                             if( aCurrCC->bIsSpecial )
     980           0 :                                 bTreatSpecial = true;
     981             : 
     982             :                             // remove and delete aCurrCC element from list (we've now merged its content)
     983           0 :                             aCurrCC = aCCList.erase( aCurrCC );
     984             : 
     985             :                             // at least one component changed, need to rescan everything
     986           0 :                             bSomeComponentsChanged = true;
     987             :                         }
     988             :                         else
     989             :                         {
     990           0 :                             ++aCurrCC;
     991             :                         }
     992             :                     }
     993             :                 }
     994             :                 while( bSomeComponentsChanged );
     995             :             }
     996             : 
     997             :             //
     998             :             //  STAGE 2.2: Determine special state for cc element
     999             :             //  =================================================
    1000             :             //
    1001             : 
    1002             :             // now test whether the whole connected component must be
    1003             :             // treated specially (i.e. rendered as a bitmap): if the
    1004             :             // added action is the very first action, or all actions
    1005             :             // before it are completely transparent, the connected
    1006             :             // component need not be treated specially, not even if
    1007             :             // the added action contains transparency. This is because
    1008             :             // painting of transparent objects on _white background_
    1009             :             // works without alpha compositing (you just calculate the
    1010             :             // color). Note that for the test "all objects before me
    1011             :             // are transparent" no sorting is necessary, since the
    1012             :             // added metaaction pCurrAct is always in the order the
    1013             :             // metafile is painted. Generally, the order of the
    1014             :             // metaactions in the ConnectedComponents are not
    1015             :             // guaranteed to be the same as in the metafile.
    1016           0 :             if( bTreatSpecial )
    1017             :             {
    1018             :                 // prev component(s) special -> this one, too
    1019           0 :                 aTotalComponents.bIsSpecial = true;
    1020             :             }
    1021           0 :             else if( !ImplIsActionSpecial( *pCurrAct ) )
    1022             :             {
    1023             :                 // added action and none of prev components special ->
    1024             :                 // this one normal, too
    1025           0 :                 aTotalComponents.bIsSpecial = false;
    1026             :             }
    1027             :             else
    1028             :             {
    1029             :                 // added action is special and none of prev components
    1030             :                 // special -> do the detailed tests
    1031             : 
    1032             :                 // can the action handle transparency correctly
    1033             :                 // (i.e. when painted on white background, does the
    1034             :                 // action still look correct)?
    1035           0 :                 if( !ImplIsActionHandlingTransparency( *pCurrAct ) )
    1036             :                 {
    1037             :                     // no, action cannot handle its transparency on
    1038             :                     // a printer device, render to bitmap
    1039           0 :                     aTotalComponents.bIsSpecial = true;
    1040             :                 }
    1041             :                 else
    1042             :                 {
    1043             :                     // yes, action can handle its transparency, so
    1044             :                     // check whether we're on white background
    1045           0 :                     if( aTotalComponents.aComponentList.empty() )
    1046             :                     {
    1047             :                         // nothing between pCurrAct and page
    1048             :                         // background -> don't be special
    1049           0 :                         aTotalComponents.bIsSpecial = false;
    1050             :                     }
    1051             :                     else
    1052             :                     {
    1053             :                         // #107169# Fixes abnove now ensure that _no_
    1054             :                         // object in the list is fully transparent. Thus,
    1055             :                         // if the component list is not empty above, we
    1056             :                         // must assume that we have to treat this
    1057             :                         // component special.
    1058             : 
    1059             :                         // there are non-transparent objects between
    1060             :                         // pCurrAct and the empty sheet of paper -> be
    1061             :                         // special, then
    1062           0 :                         aTotalComponents.bIsSpecial = true;
    1063             :                     }
    1064             :                 }
    1065             :             }
    1066             : 
    1067             : 
    1068             :             //
    1069             :             //  STAGE 2.3: Add newly generated CC list element
    1070             :             //  ==============================================
    1071             :             //
    1072             : 
    1073             :             // set new bounds and add action to list
    1074           0 :             aTotalComponents.aBounds = aTotalBounds;
    1075             :             aTotalComponents.aComponentList.push_back(
    1076             :                 ::std::make_pair(
    1077           0 :                     pCurrAct, nActionNum) );
    1078             : 
    1079             :             // add aTotalComponents as a new entry to aCCList
    1080           0 :             aCCList.push_back( aTotalComponents );
    1081             : 
    1082             :             DBG_ASSERT( !aTotalComponents.aComponentList.empty(),
    1083             :                         "Printer::GetPreparedMetaFile empty component" );
    1084             :             DBG_ASSERT( !aTotalComponents.aBounds.IsEmpty() ||
    1085             :                         (aTotalComponents.aBounds.IsEmpty() && aTotalComponents.aComponentList.size() == 1),
    1086             :                         "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
    1087             :             DBG_ASSERT( !aTotalComponents.bIsFullyTransparent ||
    1088             :                         (aTotalComponents.bIsFullyTransparent && aTotalComponents.aComponentList.size() == 1),
    1089             :                         "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
    1090           0 :         }
    1091             : 
    1092             :         // well now, we've got the list of disjunct connected
    1093             :         // components. Now we've got to create a map, which contains
    1094             :         // the corresponding aCCList element for every
    1095             :         // metaaction. Later on, we always process the complete
    1096             :         // metafile for each bitmap to be generated, but switch on
    1097             :         // output only for actions contained in the then current
    1098             :         // aCCList element. This ensures correct mapmode and attribute
    1099             :         // settings for all cases.
    1100             : 
    1101             :         // maps mtf actions to CC list entries
    1102           0 :         ::std::vector< const ConnectedComponents* > aCCList_MemberMap( rInMtf.GetActionSize() );
    1103             : 
    1104             :         // iterate over all aCCList members and their contained metaactions
    1105           0 :         ConnectedComponentsList::iterator       aCurr( aCCList.begin() );
    1106           0 :         const ConnectedComponentsList::iterator aLast( aCCList.end() );
    1107           0 :         for( ; aCurr != aLast; ++aCurr )
    1108             :         {
    1109           0 :             ComponentList::iterator       aCurrentAction( aCurr->aComponentList.begin() );
    1110           0 :             const ComponentList::iterator aLastAction( aCurr->aComponentList.end() );
    1111           0 :             for( ; aCurrentAction != aLastAction; ++aCurrentAction )
    1112             :             {
    1113             :                 // set pointer to aCCList element for corresponding index
    1114           0 :                 aCCList_MemberMap[ aCurrentAction->second ] = &(*aCurr);
    1115             :             }
    1116             :         }
    1117             : 
    1118             :         //
    1119             :         //  STAGE 3.1: Output background mtf actions (if there are any)
    1120             :         //  ===========================================================
    1121             :         //
    1122             : 
    1123           0 :         ComponentList::iterator       aCurrAct( aBackgroundComponent.aComponentList.begin() );
    1124           0 :         const ComponentList::iterator aLastAct( aBackgroundComponent.aComponentList.end() );
    1125           0 :         for( ; aCurrAct != aLastAct; ++aCurrAct )
    1126             :         {
    1127             :             // simply add this action (above, we inserted the actions
    1128             :             // starting at index 0 up to and including nLastBgAction)
    1129           0 :             rOutMtf.AddAction( ( aCurrAct->first->Duplicate(), aCurrAct->first ) );
    1130             :         }
    1131             : 
    1132             : 
    1133             :         //
    1134             :         //  STAGE 3.2: Generate banded bitmaps for special regions
    1135             :         //  ====================================================
    1136             :         //
    1137             : 
    1138           0 :         Point aPageOffset;
    1139           0 :         Size aTmpSize( GetOutputSizePixel() );
    1140           0 :         if( mpPDFWriter )
    1141             :         {
    1142           0 :             aTmpSize = mpPDFWriter->getCurPageSize();
    1143           0 :             aTmpSize = LogicToPixel( aTmpSize, MapMode( MAP_POINT ) );
    1144             : 
    1145             :             // also add error code to PDFWriter
    1146           0 :             mpPDFWriter->insertError( vcl::PDFWriter::Warning_Transparency_Converted );
    1147             :         }
    1148           0 :         else if( meOutDevType == OUTDEV_PRINTER )
    1149             :         {
    1150           0 :             Printer* pThis = dynamic_cast<Printer*>(this);
    1151           0 :             aPageOffset = pThis->GetPageOffsetPixel();
    1152           0 :             aPageOffset = Point( 0, 0 ) - aPageOffset;
    1153           0 :             aTmpSize  = pThis->GetPaperSizePixel();
    1154             :         }
    1155           0 :         const Rectangle aOutputRect( aPageOffset, aTmpSize );
    1156           0 :         bool bTiling = dynamic_cast<Printer*>(this) != NULL;
    1157             : 
    1158             :         // iterate over all aCCList members and generate bitmaps for the special ones
    1159           0 :         for( aCurr = aCCList.begin(); aCurr != aLast; ++aCurr )
    1160             :         {
    1161           0 :             if( aCurr->bIsSpecial )
    1162             :             {
    1163           0 :                 Rectangle aBoundRect( aCurr->aBounds );
    1164           0 :                 aBoundRect.Intersection( aOutputRect );
    1165             : 
    1166           0 :                 const double fBmpArea( (double) aBoundRect.GetWidth() * aBoundRect.GetHeight() );
    1167           0 :                 const double fOutArea( (double) aOutputRect.GetWidth() * aOutputRect.GetHeight() );
    1168             : 
    1169             :                 // check if output doesn't exceed given size
    1170           0 :                 if( bReduceTransparency && bTransparencyAutoMode && ( fBmpArea > ( 0.25 * fOutArea ) ) )
    1171             :                 {
    1172             :                     // output normally. Therefore, we simply clear the
    1173             :                     // special attribute, as everything non-special is
    1174             :                     // copied to rOutMtf further below.
    1175           0 :                     aCurr->bIsSpecial = false;
    1176             :                 }
    1177             :                 else
    1178             :                 {
    1179             :                     // create new bitmap action first
    1180           0 :                     if( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
    1181             :                     {
    1182           0 :                         Point           aDstPtPix( aBoundRect.TopLeft() );
    1183           0 :                         Size            aDstSzPix;
    1184             : 
    1185           0 :                         VirtualDevice   aMapVDev;   // here, we record only mapmode information
    1186           0 :                         aMapVDev.EnableOutput(sal_False);
    1187             : 
    1188           0 :                         VirtualDevice   aPaintVDev; // into this one, we render.
    1189           0 :                         aPaintVDev.SetBackground( aBackgroundComponent.aBgColor );
    1190             : 
    1191           0 :                         rOutMtf.AddAction( new MetaPushAction( PUSH_MAPMODE ) );
    1192           0 :                         rOutMtf.AddAction( new MetaMapModeAction() );
    1193             : 
    1194           0 :                         aPaintVDev.SetDrawMode( GetDrawMode() );
    1195             : 
    1196           0 :                         while( aDstPtPix.Y() <= aBoundRect.Bottom() )
    1197             :                         {
    1198           0 :                             aDstPtPix.X() = aBoundRect.Left();
    1199           0 :                             aDstSzPix = bTiling ? Size( MAX_TILE_WIDTH, MAX_TILE_HEIGHT ) : aBoundRect.GetSize();
    1200             : 
    1201           0 :                             if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1L ) > aBoundRect.Bottom() )
    1202           0 :                                 aDstSzPix.Height() = aBoundRect.Bottom() - aDstPtPix.Y() + 1L;
    1203             : 
    1204           0 :                             while( aDstPtPix.X() <= aBoundRect.Right() )
    1205             :                             {
    1206           0 :                                 if( ( aDstPtPix.X() + aDstSzPix.Width() - 1L ) > aBoundRect.Right() )
    1207           0 :                                     aDstSzPix.Width() = aBoundRect.Right() - aDstPtPix.X() + 1L;
    1208             : 
    1209           0 :                                 if( !Rectangle( aDstPtPix, aDstSzPix ).Intersection( aBoundRect ).IsEmpty() &&
    1210           0 :                                     aPaintVDev.SetOutputSizePixel( aDstSzPix ) )
    1211             :                                 {
    1212           0 :                                     aPaintVDev.Push();
    1213           0 :                                     aMapVDev.Push();
    1214             : 
    1215           0 :                                     aMapVDev.mnDPIX = aPaintVDev.mnDPIX = mnDPIX;
    1216           0 :                                     aMapVDev.mnDPIY = aPaintVDev.mnDPIY = mnDPIY;
    1217             : 
    1218           0 :                                     aPaintVDev.EnableOutput(sal_False);
    1219             : 
    1220             :                                     // iterate over all actions
    1221           0 :                                     for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
    1222             :                                          pCurrAct;
    1223           0 :                                          pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
    1224             :                                     {
    1225             :                                         // enable output only for
    1226             :                                         // actions that are members of
    1227             :                                         // the current aCCList element
    1228             :                                         // (aCurr)
    1229           0 :                                         if( aCCList_MemberMap[nActionNum] == &(*aCurr) )
    1230           0 :                                             aPaintVDev.EnableOutput(sal_True);
    1231             : 
    1232             :                                         // but process every action
    1233           0 :                                         const sal_uInt16 nType( pCurrAct->GetType() );
    1234             : 
    1235           0 :                                         if( META_MAPMODE_ACTION == nType )
    1236             :                                         {
    1237           0 :                                             pCurrAct->Execute( &aMapVDev );
    1238             : 
    1239           0 :                                             MapMode     aMtfMap( aMapVDev.GetMapMode() );
    1240           0 :                                             const Point aNewOrg( aMapVDev.PixelToLogic( aDstPtPix ) );
    1241             : 
    1242           0 :                                             aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
    1243           0 :                                             aPaintVDev.SetMapMode( aMtfMap );
    1244             :                                         }
    1245           0 :                                         else if( ( META_PUSH_ACTION == nType ) || ( META_POP_ACTION ) == nType )
    1246             :                                         {
    1247           0 :                                             pCurrAct->Execute( &aMapVDev );
    1248           0 :                                             pCurrAct->Execute( &aPaintVDev );
    1249             :                                         }
    1250           0 :                                         else if( META_GRADIENT_ACTION == nType )
    1251             :                                         {
    1252           0 :                                             MetaGradientAction* pGradientAction = static_cast<MetaGradientAction*>(pCurrAct);
    1253           0 :                                             Printer* pPrinter = dynamic_cast< Printer* >(this);
    1254           0 :                                             if( pPrinter )
    1255           0 :                                                 pPrinter->DrawGradientEx( &aPaintVDev, pGradientAction->GetRect(), pGradientAction->GetGradient() );
    1256             :                                             else
    1257           0 :                                                 DrawGradient( pGradientAction->GetRect(), pGradientAction->GetGradient() );
    1258             :                                         }
    1259             :                                         else
    1260             :                                         {
    1261           0 :                                             pCurrAct->Execute( &aPaintVDev );
    1262             :                                         }
    1263             : 
    1264           0 :                                         if( !( nActionNum % 8 ) )
    1265           0 :                                             Application::Reschedule();
    1266             :                                     }
    1267             : 
    1268           0 :                                     const sal_Bool bOldMap = mbMap;
    1269           0 :                                     mbMap = aPaintVDev.mbMap = sal_False;
    1270             : 
    1271           0 :                                     Bitmap aBandBmp( aPaintVDev.GetBitmap( Point(), aDstSzPix ) );
    1272             : 
    1273             :                                     // scale down bitmap, if requested
    1274           0 :                                     if( bDownsampleBitmaps )
    1275             :                                     {
    1276             :                                         aBandBmp = GetDownsampledBitmap( aDstSzPix,
    1277             :                                                                          Point(), aBandBmp.GetSizePixel(),
    1278           0 :                                                                          aBandBmp, nMaxBmpDPIX, nMaxBmpDPIY );
    1279             :                                     }
    1280             : 
    1281           0 :                                     rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
    1282           0 :                                     rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) );
    1283           0 :                                     rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
    1284             : 
    1285           0 :                                     aPaintVDev.mbMap = sal_True;
    1286           0 :                                     mbMap = bOldMap;
    1287           0 :                                     aMapVDev.Pop();
    1288           0 :                                     aPaintVDev.Pop();
    1289             :                                 }
    1290             : 
    1291             :                                 // overlapping bands to avoid missing lines (e.g. PostScript)
    1292           0 :                                 aDstPtPix.X() += aDstSzPix.Width();
    1293             :                             }
    1294             : 
    1295             :                             // overlapping bands to avoid missing lines (e.g. PostScript)
    1296           0 :                             aDstPtPix.Y() += aDstSzPix.Height();
    1297             :                         }
    1298             : 
    1299           0 :                         rOutMtf.AddAction( new MetaPopAction() );
    1300             :                     }
    1301             :                 }
    1302             :             }
    1303             :         }
    1304             : 
    1305             :         // clean up aMapModeVDev
    1306           0 :         nCount = aMapModeVDev.GetGCStackDepth();
    1307           0 :         while( nCount-- )
    1308           0 :             aMapModeVDev.Pop();
    1309             : 
    1310             :         //
    1311             :         //  STAGE 4: Copy actions to output metafile
    1312             :         //  ========================================
    1313             :         //
    1314             : 
    1315             :         // iterate over all actions and duplicate the ones not in a
    1316             :         // special aCCList member into rOutMtf
    1317           0 :         for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
    1318             :              pCurrAct;
    1319           0 :              pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
    1320             :         {
    1321           0 :             const ConnectedComponents* pCurrAssociatedComponent = aCCList_MemberMap[nActionNum];
    1322             : 
    1323             :             // NOTE: This relies on the fact that map-mode or draw
    1324             :             // mode changing actions are solitary aCCList elements and
    1325             :             // have empty bounding boxes, see comment on stage 2.1
    1326             :             // above
    1327           0 :             if( pCurrAssociatedComponent &&
    1328           0 :                 (pCurrAssociatedComponent->aBounds.IsEmpty() ||
    1329           0 :                  !pCurrAssociatedComponent->bIsSpecial) )
    1330             :             {
    1331             :                 // #107169# Treat transparent bitmaps special, if they
    1332             :                 // are the first (or sole) action in their bounds
    1333             :                 // list. Note that we previously ensured that no
    1334             :                 // fully-transparent objects are before us here.
    1335           0 :                 if( ImplIsActionHandlingTransparency( *pCurrAct ) &&
    1336           0 :                     pCurrAssociatedComponent->aComponentList.begin()->first == pCurrAct )
    1337             :                 {
    1338             :                     // convert actions, where masked-out parts are of
    1339             :                     // given background color
    1340             :                     ImplConvertTransparentAction(rOutMtf,
    1341             :                                                  *pCurrAct,
    1342             :                                                  aMapModeVDev,
    1343           0 :                                                  aBackgroundComponent.aBgColor);
    1344             :                 }
    1345             :                 else
    1346             :                 {
    1347             :                     // simply add this action
    1348           0 :                     rOutMtf.AddAction( ( pCurrAct->Duplicate(), pCurrAct ) );
    1349             :                 }
    1350             : 
    1351           0 :                 pCurrAct->Execute(&aMapModeVDev);
    1352             :             }
    1353             :         }
    1354             : 
    1355           0 :         rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() );
    1356           0 :         rOutMtf.SetPrefSize( rInMtf.GetPrefSize() );
    1357             :     }
    1358           0 :     return bTransparent;
    1359             : }
    1360             : 
    1361             : // -----------------------------------------------------------------------------
    1362             : 
    1363           0 : Bitmap OutputDevice::GetDownsampledBitmap( const Size& rDstSz,
    1364             :                                            const Point& rSrcPt, const Size& rSrcSz,
    1365             :                                            const Bitmap& rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY )
    1366             : {
    1367           0 :     Bitmap aBmp( rBmp );
    1368             : 
    1369           0 :     if( !aBmp.IsEmpty() )
    1370             :     {
    1371           0 :         Point           aPoint;
    1372           0 :         const Rectangle aBmpRect( aPoint, aBmp.GetSizePixel() );
    1373           0 :         Rectangle       aSrcRect( rSrcPt, rSrcSz );
    1374             : 
    1375             :         // do cropping if neccessary
    1376           0 :         if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
    1377             :         {
    1378           0 :             if( !aSrcRect.IsEmpty() )
    1379           0 :                 aBmp.Crop( aSrcRect );
    1380             :             else
    1381           0 :                 aBmp.SetEmpty();
    1382             :         }
    1383             : 
    1384           0 :         if( !aBmp.IsEmpty() )
    1385             :         {
    1386             :             // do downsampling if neccessary
    1387           0 :             Size aDstSizeTwip( PixelToLogic( LogicToPixel( rDstSz ), MAP_TWIP ) );
    1388             : 
    1389             :             // #103209# Normalize size (mirroring has to happen outside of this method)
    1390           0 :             aDstSizeTwip = Size( labs(aDstSizeTwip.Width()), labs(aDstSizeTwip.Height()) );
    1391             : 
    1392           0 :             const Size      aBmpSize( aBmp.GetSizePixel() );
    1393           0 :             const double    fBmpPixelX = aBmpSize.Width();
    1394           0 :             const double    fBmpPixelY = aBmpSize.Height();
    1395           0 :             const double    fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
    1396           0 :             const double    fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
    1397             : 
    1398             :             // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
    1399           0 :             if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
    1400             :                   ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
    1401             :                 ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
    1402             :             {
    1403             :                 // do scaling
    1404           0 :                 Size            aNewBmpSize;
    1405           0 :                 const double    fBmpWH = fBmpPixelX / fBmpPixelY;
    1406           0 :                 const double    fMaxWH = fMaxPixelX / fMaxPixelY;
    1407             : 
    1408           0 :                 if( fBmpWH < fMaxWH )
    1409             :                 {
    1410           0 :                     aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH );
    1411           0 :                     aNewBmpSize.Height() = FRound( fMaxPixelY );
    1412             :                 }
    1413           0 :                 else if( fBmpWH > 0.0 )
    1414             :                 {
    1415           0 :                     aNewBmpSize.Width() = FRound( fMaxPixelX );
    1416           0 :                     aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH);
    1417             :                 }
    1418             : 
    1419           0 :                 if( aNewBmpSize.Width() && aNewBmpSize.Height() )
    1420           0 :                     aBmp.Scale( aNewBmpSize );
    1421             :                 else
    1422           0 :                     aBmp.SetEmpty();
    1423             :             }
    1424             :         }
    1425             :     }
    1426             : 
    1427           0 :     return aBmp;
    1428             : }
    1429             : 
    1430             : // -----------------------------------------------------------------------------
    1431             : 
    1432           0 : void Printer::DrawGradientEx( OutputDevice* pOut, const Rectangle& rRect, const Gradient& rGradient )
    1433             : {
    1434           0 :     const PrinterOptions& rPrinterOptions = GetPrinterOptions();
    1435             : 
    1436           0 :     if( rPrinterOptions.IsReduceGradients() )
    1437             :     {
    1438           0 :         if( PRINTER_GRADIENT_STRIPES == rPrinterOptions.GetReducedGradientMode() )
    1439             :         {
    1440           0 :             if( !rGradient.GetSteps() || ( rGradient.GetSteps() > rPrinterOptions.GetReducedGradientStepCount() ) )
    1441             :             {
    1442           0 :                 Gradient aNewGradient( rGradient );
    1443             : 
    1444           0 :                 aNewGradient.SetSteps( rPrinterOptions.GetReducedGradientStepCount() );
    1445           0 :                 pOut->DrawGradient( rRect, aNewGradient );
    1446             :             }
    1447             :             else
    1448           0 :                 pOut->DrawGradient( rRect, rGradient );
    1449             :         }
    1450             :         else
    1451             :         {
    1452           0 :             const Color&    rStartColor = rGradient.GetStartColor();
    1453           0 :             const Color&    rEndColor = rGradient.GetEndColor();
    1454           0 :             const long      nR = ( ( (long) rStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100L +
    1455           0 :                                    ( (long) rEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
    1456           0 :             const long      nG = ( ( (long) rStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100L +
    1457           0 :                                    ( (long) rEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
    1458           0 :             const long      nB = ( ( (long) rStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100L +
    1459           0 :                                    ( (long) rEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
    1460           0 :             const Color     aColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB );
    1461             : 
    1462           0 :             pOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
    1463           0 :             pOut->SetLineColor( aColor );
    1464           0 :             pOut->SetFillColor( aColor );
    1465           0 :             pOut->DrawRect( rRect );
    1466           0 :             pOut->Pop();
    1467             :         }
    1468             :     }
    1469             :     else
    1470           0 :         pOut->DrawGradient( rRect, rGradient );
    1471           0 : }
    1472             : 
    1473             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10