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

Generated by: LCOV version 1.10