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

Generated by: LCOV version 1.10