1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
29 #include <tools/debug.hxx>
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/bitmapaccess.hxx>
40 #include "pdfwriter_impl.hxx"
42 #define MAX_TILE_WIDTH 1024
43 #define MAX_TILE_HEIGHT 1024
45 typedef ::std::pair
< MetaAction
*, int > Component
; // MetaAction plus index in metafile
47 typedef ::std::list
< Component
> ComponentList
;
49 // List of (intersecting) actions, plus overall bounds
50 struct ConnectedComponents
52 ConnectedComponents() :
57 bIsFullyTransparent(false)
60 ComponentList aComponentList
;
64 bool bIsFullyTransparent
;
67 typedef ::std::list
< ConnectedComponents
> ConnectedComponentsList
;
71 /** \#i10613# Extracted from Printer::GetPreparedMetaFile. Returns true
72 if given action requires special transparency handling
74 bool IsTransparentAction( const MetaAction
& rAct
)
76 switch( rAct
.GetType() )
78 case MetaActionType::Transparent
:
81 case MetaActionType::FLOATTRANSPARENT
:
84 case MetaActionType::BMPEX
:
85 return static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx().IsTransparent();
87 case MetaActionType::BMPEXSCALE
:
88 return static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx().IsTransparent();
90 case MetaActionType::BMPEXSCALEPART
:
91 return static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetBitmapEx().IsTransparent();
99 /** Determines whether the action can handle transparency correctly
100 (i.e. when painted on white background, does the action still look
103 bool DoesActionHandleTransparency( const MetaAction
& rAct
)
105 // MetaActionType::FLOATTRANSPARENT 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.
110 // the remainder can handle printing itself correctly on a uniform
112 switch( rAct
.GetType() )
114 case MetaActionType::Transparent
:
115 case MetaActionType::BMPEX
:
116 case MetaActionType::BMPEXSCALE
:
117 case MetaActionType::BMPEXSCALEPART
:
125 /** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
126 yes, return true and update o_rBgColor
128 bool checkRect( Rectangle
& io_rPrevRect
,
130 const Rectangle
& rCurrRect
,
131 OutputDevice
& rMapModeVDev
)
133 // shape needs to fully cover previous content, and have uniform
136 rMapModeVDev
.LogicToPixel(rCurrRect
).IsInside(io_rPrevRect
) &&
137 rMapModeVDev
.IsFillColor() );
141 io_rPrevRect
= rCurrRect
;
142 o_rBgColor
= rMapModeVDev
.GetFillColor();
148 /** #107169# Convert BitmapEx to Bitmap with appropriately blended
149 color. Convert MetaTransparentAction to plain polygon,
150 appropriately colored
153 Add converted actions to this metafile
155 void ImplConvertTransparentAction( GDIMetaFile
& o_rMtf
,
156 const MetaAction
& rAct
,
157 const OutputDevice
& rStateOutDev
,
160 if( rAct
.GetType() == MetaActionType::Transparent
)
162 const MetaTransparentAction
* pTransAct
= static_cast<const MetaTransparentAction
*>(&rAct
);
163 sal_uInt16
nTransparency( pTransAct
->GetTransparence() );
165 // #i10613# Respect transparency for draw color
168 o_rMtf
.AddAction( new MetaPushAction( PushFlags::LINECOLOR
|PushFlags::FILLCOLOR
) );
170 // assume white background for alpha blending
171 Color
aLineColor( rStateOutDev
.GetLineColor() );
172 aLineColor
.SetRed( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aLineColor
.GetRed()) / 100L ) );
173 aLineColor
.SetGreen( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aLineColor
.GetGreen()) / 100L ) );
174 aLineColor
.SetBlue( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aLineColor
.GetBlue()) / 100L ) );
175 o_rMtf
.AddAction( new MetaLineColorAction(aLineColor
, true) );
177 Color
aFillColor( rStateOutDev
.GetFillColor() );
178 aFillColor
.SetRed( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aFillColor
.GetRed()) / 100L ) );
179 aFillColor
.SetGreen( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aFillColor
.GetGreen()) / 100L ) );
180 aFillColor
.SetBlue( static_cast<sal_uInt8
>( (255L*nTransparency
+ (100L - nTransparency
)*aFillColor
.GetBlue()) / 100L ) );
181 o_rMtf
.AddAction( new MetaFillColorAction(aFillColor
, true) );
184 o_rMtf
.AddAction( new MetaPolyPolygonAction(pTransAct
->GetPolyPolygon()) );
187 o_rMtf
.AddAction( new MetaPopAction() );
193 switch( rAct
.GetType() )
195 case MetaActionType::BMPEX
:
196 aBmpEx
= static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx();
199 case MetaActionType::BMPEXSCALE
:
200 aBmpEx
= static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx();
203 case MetaActionType::BMPEXSCALEPART
:
204 aBmpEx
= static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx();
207 case MetaActionType::Transparent
:
210 OSL_FAIL("Printer::GetPreparedMetafile impossible state reached");
214 Bitmap
aBmp( aBmpEx
.GetBitmap() );
215 if( !aBmpEx
.IsAlpha() )
218 BitmapReadAccess
* pRA
= aBmp
.AcquireReadAccess();
221 return; // what else should I do?
223 Color
aActualColor( aBgColor
);
225 if( pRA
->HasPalette() )
226 aActualColor
= pRA
->GetBestPaletteColor( aBgColor
).operator Color();
228 Bitmap::ReleaseAccess(pRA
);
230 // did we get true white?
231 if( aActualColor
.GetColorError( aBgColor
) )
233 // no, create truecolor bitmap, then
234 aBmp
.Convert( BMP_CONVERSION_24BIT
);
236 // fill masked out areas white
237 aBmp
.Replace( aBmpEx
.GetMask(), aBgColor
);
241 // fill masked out areas white
242 aBmp
.Replace( aBmpEx
.GetMask(), aActualColor
);
247 // blend with alpha channel
248 aBmp
.Convert( BMP_CONVERSION_24BIT
);
249 aBmp
.Blend(aBmpEx
.GetAlpha(),aBgColor
);
252 // add corresponding action
253 switch( rAct
.GetType() )
255 case MetaActionType::BMPEX
:
256 o_rMtf
.AddAction( new MetaBmpAction(
257 static_cast<const MetaBmpExAction
&>(rAct
).GetPoint(),
260 case MetaActionType::BMPEXSCALE
:
261 o_rMtf
.AddAction( new MetaBmpScaleAction(
262 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetPoint(),
263 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetSize(),
266 case MetaActionType::BMPEXSCALEPART
:
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(),
275 OSL_FAIL("Unexpected case");
281 // #i10613# Extracted from ImplCheckRect::ImplCreate
282 // Returns true, if given action creates visible (i.e. non-transparent) output
283 bool ImplIsNotTransparent( const MetaAction
& rAct
, const OutputDevice
& rOut
)
285 const bool bLineTransparency( !rOut
.IsLineColor() || rOut
.GetLineColor().GetTransparency() == 255 );
286 const bool bFillTransparency( !rOut
.IsFillColor() || rOut
.GetFillColor().GetTransparency() == 255 );
289 switch( rAct
.GetType() )
291 case MetaActionType::POINT
:
292 if( !bLineTransparency
)
296 case MetaActionType::LINE
:
297 if( !bLineTransparency
)
301 case MetaActionType::RECT
:
302 if( !bLineTransparency
|| !bFillTransparency
)
306 case MetaActionType::ROUNDRECT
:
307 if( !bLineTransparency
|| !bFillTransparency
)
311 case MetaActionType::ELLIPSE
:
312 if( !bLineTransparency
|| !bFillTransparency
)
316 case MetaActionType::ARC
:
317 if( !bLineTransparency
|| !bFillTransparency
)
321 case MetaActionType::PIE
:
322 if( !bLineTransparency
|| !bFillTransparency
)
326 case MetaActionType::CHORD
:
327 if( !bLineTransparency
|| !bFillTransparency
)
331 case MetaActionType::POLYLINE
:
332 if( !bLineTransparency
)
336 case MetaActionType::POLYGON
:
337 if( !bLineTransparency
|| !bFillTransparency
)
341 case MetaActionType::POLYPOLYGON
:
342 if( !bLineTransparency
|| !bFillTransparency
)
346 case MetaActionType::TEXT
:
348 const MetaTextAction
& rTextAct
= static_cast<const MetaTextAction
&>(rAct
);
349 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
350 if (!aString
.isEmpty())
355 case MetaActionType::TEXTARRAY
:
357 const MetaTextArrayAction
& rTextAct
= static_cast<const MetaTextArrayAction
&>(rAct
);
358 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
359 if (!aString
.isEmpty())
364 case MetaActionType::PIXEL
:
365 case MetaActionType::BMP
:
366 case MetaActionType::BMPSCALE
:
367 case MetaActionType::BMPSCALEPART
:
368 case MetaActionType::BMPEX
:
369 case MetaActionType::BMPEXSCALE
:
370 case MetaActionType::BMPEXSCALEPART
:
371 case MetaActionType::MASK
:
372 case MetaActionType::MASKSCALE
:
373 case MetaActionType::MASKSCALEPART
:
374 case MetaActionType::GRADIENT
:
375 case MetaActionType::GRADIENTEX
:
376 case MetaActionType::HATCH
:
377 case MetaActionType::WALLPAPER
:
378 case MetaActionType::Transparent
:
379 case MetaActionType::FLOATTRANSPARENT
:
380 case MetaActionType::EPS
:
381 case MetaActionType::TEXTRECT
:
382 case MetaActionType::STRETCHTEXT
:
383 case MetaActionType::TEXTLINE
:
384 // all other actions: generate non-transparent output
395 // #i10613# Extracted from ImplCheckRect::ImplCreate
396 Rectangle
ImplCalcActionBounds( const MetaAction
& rAct
, const OutputDevice
& rOut
)
398 Rectangle aActionBounds
;
400 switch( rAct
.GetType() )
402 case MetaActionType::PIXEL
:
403 aActionBounds
= Rectangle( static_cast<const MetaPixelAction
&>(rAct
).GetPoint(), Size( 1, 1 ) );
406 case MetaActionType::POINT
:
407 aActionBounds
= Rectangle( static_cast<const MetaPointAction
&>(rAct
).GetPoint(), Size( 1, 1 ) );
410 case MetaActionType::LINE
:
412 const MetaLineAction
& rMetaLineAction
= static_cast<const MetaLineAction
&>(rAct
);
413 aActionBounds
= Rectangle( rMetaLineAction
.GetStartPoint(), rMetaLineAction
.GetEndPoint() );
414 aActionBounds
.Justify();
415 const long nLineWidth(rMetaLineAction
.GetLineInfo().GetWidth());
418 const long nHalfLineWidth((nLineWidth
+ 1) / 2);
419 aActionBounds
.Left() -= nHalfLineWidth
;
420 aActionBounds
.Top() -= nHalfLineWidth
;
421 aActionBounds
.Right() += nHalfLineWidth
;
422 aActionBounds
.Bottom() += nHalfLineWidth
;
427 case MetaActionType::RECT
:
428 aActionBounds
= static_cast<const MetaRectAction
&>(rAct
).GetRect();
431 case MetaActionType::ROUNDRECT
:
432 aActionBounds
= tools::Polygon( static_cast<const MetaRoundRectAction
&>(rAct
).GetRect(),
433 static_cast<const MetaRoundRectAction
&>(rAct
).GetHorzRound(),
434 static_cast<const MetaRoundRectAction
&>(rAct
).GetVertRound() ).GetBoundRect();
437 case MetaActionType::ELLIPSE
:
439 const Rectangle
& rRect
= static_cast<const MetaEllipseAction
&>(rAct
).GetRect();
440 aActionBounds
= tools::Polygon( rRect
.Center(),
441 rRect
.GetWidth() >> 1,
442 rRect
.GetHeight() >> 1 ).GetBoundRect();
446 case MetaActionType::ARC
:
447 aActionBounds
= tools::Polygon( static_cast<const MetaArcAction
&>(rAct
).GetRect(),
448 static_cast<const MetaArcAction
&>(rAct
).GetStartPoint(),
449 static_cast<const MetaArcAction
&>(rAct
).GetEndPoint(), POLY_ARC
).GetBoundRect();
452 case MetaActionType::PIE
:
453 aActionBounds
= tools::Polygon( static_cast<const MetaPieAction
&>(rAct
).GetRect(),
454 static_cast<const MetaPieAction
&>(rAct
).GetStartPoint(),
455 static_cast<const MetaPieAction
&>(rAct
).GetEndPoint(), POLY_PIE
).GetBoundRect();
458 case MetaActionType::CHORD
:
459 aActionBounds
= tools::Polygon( static_cast<const MetaChordAction
&>(rAct
).GetRect(),
460 static_cast<const MetaChordAction
&>(rAct
).GetStartPoint(),
461 static_cast<const MetaChordAction
&>(rAct
).GetEndPoint(), POLY_CHORD
).GetBoundRect();
464 case MetaActionType::POLYLINE
:
466 const MetaPolyLineAction
& rMetaPolyLineAction
= static_cast<const MetaPolyLineAction
&>(rAct
);
467 aActionBounds
= rMetaPolyLineAction
.GetPolygon().GetBoundRect();
468 const long nLineWidth(rMetaPolyLineAction
.GetLineInfo().GetWidth());
471 const long nHalfLineWidth((nLineWidth
+ 1) / 2);
472 aActionBounds
.Left() -= nHalfLineWidth
;
473 aActionBounds
.Top() -= nHalfLineWidth
;
474 aActionBounds
.Right() += nHalfLineWidth
;
475 aActionBounds
.Bottom() += nHalfLineWidth
;
480 case MetaActionType::POLYGON
:
481 aActionBounds
= static_cast<const MetaPolygonAction
&>(rAct
).GetPolygon().GetBoundRect();
484 case MetaActionType::POLYPOLYGON
:
485 aActionBounds
= static_cast<const MetaPolyPolygonAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
488 case MetaActionType::BMP
:
489 aActionBounds
= Rectangle( static_cast<const MetaBmpAction
&>(rAct
).GetPoint(),
490 rOut
.PixelToLogic( static_cast<const MetaBmpAction
&>(rAct
).GetBitmap().GetSizePixel() ) );
493 case MetaActionType::BMPSCALE
:
494 aActionBounds
= Rectangle( static_cast<const MetaBmpScaleAction
&>(rAct
).GetPoint(),
495 static_cast<const MetaBmpScaleAction
&>(rAct
).GetSize() );
498 case MetaActionType::BMPSCALEPART
:
499 aActionBounds
= Rectangle( static_cast<const MetaBmpScalePartAction
&>(rAct
).GetDestPoint(),
500 static_cast<const MetaBmpScalePartAction
&>(rAct
).GetDestSize() );
503 case MetaActionType::BMPEX
:
504 aActionBounds
= Rectangle( static_cast<const MetaBmpExAction
&>(rAct
).GetPoint(),
505 rOut
.PixelToLogic( static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx().GetSizePixel() ) );
508 case MetaActionType::BMPEXSCALE
:
509 aActionBounds
= Rectangle( static_cast<const MetaBmpExScaleAction
&>(rAct
).GetPoint(),
510 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetSize() );
513 case MetaActionType::BMPEXSCALEPART
:
514 aActionBounds
= Rectangle( static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestPoint(),
515 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestSize() );
518 case MetaActionType::MASK
:
519 aActionBounds
= Rectangle( static_cast<const MetaMaskAction
&>(rAct
).GetPoint(),
520 rOut
.PixelToLogic( static_cast<const MetaMaskAction
&>(rAct
).GetBitmap().GetSizePixel() ) );
523 case MetaActionType::MASKSCALE
:
524 aActionBounds
= Rectangle( static_cast<const MetaMaskScaleAction
&>(rAct
).GetPoint(),
525 static_cast<const MetaMaskScaleAction
&>(rAct
).GetSize() );
528 case MetaActionType::MASKSCALEPART
:
529 aActionBounds
= Rectangle( static_cast<const MetaMaskScalePartAction
&>(rAct
).GetDestPoint(),
530 static_cast<const MetaMaskScalePartAction
&>(rAct
).GetDestSize() );
533 case MetaActionType::GRADIENT
:
534 aActionBounds
= static_cast<const MetaGradientAction
&>(rAct
).GetRect();
537 case MetaActionType::GRADIENTEX
:
538 aActionBounds
= static_cast<const MetaGradientExAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
541 case MetaActionType::HATCH
:
542 aActionBounds
= static_cast<const MetaHatchAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
545 case MetaActionType::WALLPAPER
:
546 aActionBounds
= static_cast<const MetaWallpaperAction
&>(rAct
).GetRect();
549 case MetaActionType::Transparent
:
550 aActionBounds
= static_cast<const MetaTransparentAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
553 case MetaActionType::FLOATTRANSPARENT
:
554 aActionBounds
= Rectangle( static_cast<const MetaFloatTransparentAction
&>(rAct
).GetPoint(),
555 static_cast<const MetaFloatTransparentAction
&>(rAct
).GetSize() );
558 case MetaActionType::EPS
:
559 aActionBounds
= Rectangle( static_cast<const MetaEPSAction
&>(rAct
).GetPoint(),
560 static_cast<const MetaEPSAction
&>(rAct
).GetSize() );
563 case MetaActionType::TEXT
:
565 const MetaTextAction
& rTextAct
= static_cast<const MetaTextAction
&>(rAct
);
566 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
568 if (!aString
.isEmpty())
570 const Point
aPtLog( rTextAct
.GetPoint() );
572 // #105987# Use API method instead of Impl* methods
573 // #107490# Set base parameter equal to index parameter
574 rOut
.GetTextBoundRect( aActionBounds
, rTextAct
.GetText(), rTextAct
.GetIndex(),
575 rTextAct
.GetIndex(), rTextAct
.GetLen() );
576 aActionBounds
.Move( aPtLog
.X(), aPtLog
.Y() );
581 case MetaActionType::TEXTARRAY
:
583 const MetaTextArrayAction
& rTextAct
= static_cast<const MetaTextArrayAction
&>(rAct
);
584 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
586 if( !aString
.isEmpty() )
588 // #105987# ImplLayout takes everything in logical coordinates
589 SalLayout
* pSalLayout
= rOut
.ImplLayout( rTextAct
.GetText(), rTextAct
.GetIndex(),
590 rTextAct
.GetLen(), rTextAct
.GetPoint(),
591 0, rTextAct
.GetDXArray() );
594 Rectangle
aBoundRect( const_cast<OutputDevice
&>(rOut
).ImplGetTextBoundRect( *pSalLayout
) );
595 aActionBounds
= rOut
.PixelToLogic( aBoundRect
);
596 pSalLayout
->Release();
602 case MetaActionType::TEXTRECT
:
603 aActionBounds
= static_cast<const MetaTextRectAction
&>(rAct
).GetRect();
606 case MetaActionType::STRETCHTEXT
:
608 const MetaStretchTextAction
& rTextAct
= static_cast<const MetaStretchTextAction
&>(rAct
);
609 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
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 if( !aString
.isEmpty() )
618 // #105987# ImplLayout takes everything in logical coordinates
619 SalLayout
* pSalLayout
= rOut
.ImplLayout( rTextAct
.GetText(), rTextAct
.GetIndex(),
620 rTextAct
.GetLen(), rTextAct
.GetPoint(),
621 rTextAct
.GetWidth() );
624 Rectangle
aBoundRect( const_cast<OutputDevice
&>(rOut
).ImplGetTextBoundRect( *pSalLayout
) );
625 aActionBounds
= rOut
.PixelToLogic( aBoundRect
);
626 pSalLayout
->Release();
632 case MetaActionType::TEXTLINE
:
633 OSL_FAIL("MetaActionType::TEXTLINE not supported");
640 if( !aActionBounds
.IsEmpty() )
642 // fdo#40421 limit current action's output to clipped area
643 if( rOut
.IsClipRegion() )
644 return rOut
.LogicToPixel(
645 rOut
.GetClipRegion().GetBoundRect().Intersection( aActionBounds
) );
647 return rOut
.LogicToPixel( aActionBounds
);
653 } // end anon namespace
655 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
662 MetaAction
* pCurrAct
;
663 bool bTransparent( false );
667 if( ! bReduceTransparency
|| bTransparencyAutoMode
)
669 // watch for transparent drawing actions
670 for( pCurrAct
= ( (GDIMetaFile
&) rInMtf
).FirstAction();
671 pCurrAct
&& !bTransparent
;
672 pCurrAct
= ( (GDIMetaFile
&) rInMtf
).NextAction() )
674 // #i10613# determine if the action is transparency capable
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
683 if( IsTransparentAction( *pCurrAct
) )
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.
694 // nothing transparent -> just copy
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.
724 // STAGE 1: Detect background
726 // Receives uniform background content, and is _not_ merged
727 // nor checked for intersection against other aCCList elements
728 ConnectedComponents aBackgroundComponent
;
730 // create an OutputDevice to record mapmode changes and the like
731 ScopedVclPtrInstance
< VirtualDevice
> aMapModeVDev
;
732 aMapModeVDev
->mnDPIX
= mnDPIX
;
733 aMapModeVDev
->mnDPIY
= mnDPIY
;
734 aMapModeVDev
->EnableOutput(false);
736 int nLastBgAction
, nActionNum
;
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
742 bool bStillBackground
=true; // true until first non-bg action
743 nActionNum
=0; nLastBgAction
=-1;
744 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction();
745 if( rBackground
!= Color( COL_TRANSPARENT
) )
747 aBackgroundComponent
.aBgColor
= rBackground
;
748 if( meOutDevType
== OUTDEV_PRINTER
)
750 Printer
* pThis
= dynamic_cast<Printer
*>(this);
751 Point aPageOffset
= pThis
->GetPageOffsetPixel();
752 aPageOffset
= Point( 0, 0 ) - aPageOffset
;
753 Size aSize
= pThis
->GetPaperSizePixel();
754 aBackgroundComponent
.aBounds
= Rectangle( aPageOffset
, aSize
);
757 aBackgroundComponent
.aBounds
= Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
759 while( pCurrAct
&& bStillBackground
)
761 switch( pCurrAct
->GetType() )
763 case MetaActionType::RECT
:
766 aBackgroundComponent
.aBounds
,
767 aBackgroundComponent
.aBgColor
,
768 static_cast<const MetaRectAction
*>(pCurrAct
)->GetRect(),
769 *aMapModeVDev
.get()) )
770 bStillBackground
=false; // incomplete occlusion of background
772 nLastBgAction
=nActionNum
; // this _is_ background
775 case MetaActionType::POLYGON
:
777 const tools::Polygon
aPoly(
778 static_cast<const MetaPolygonAction
*>(pCurrAct
)->GetPolygon());
779 if( !basegfx::tools::isRectangle(
780 aPoly
.getB2DPolygon()) ||
782 aBackgroundComponent
.aBounds
,
783 aBackgroundComponent
.aBgColor
,
784 aPoly
.GetBoundRect(),
785 *aMapModeVDev
.get()) )
786 bStillBackground
=false; // incomplete occlusion of background
788 nLastBgAction
=nActionNum
; // this _is_ background
791 case MetaActionType::POLYPOLYGON
:
793 const tools::PolyPolygon
aPoly(
794 static_cast<const MetaPolyPolygonAction
*>(pCurrAct
)->GetPolyPolygon());
795 if( aPoly
.Count() != 1 ||
796 !basegfx::tools::isRectangle(
797 aPoly
[0].getB2DPolygon()) ||
799 aBackgroundComponent
.aBounds
,
800 aBackgroundComponent
.aBgColor
,
801 aPoly
.GetBoundRect(),
802 *aMapModeVDev
.get()) )
803 bStillBackground
=false; // incomplete occlusion of background
805 nLastBgAction
=nActionNum
; // this _is_ background
808 case MetaActionType::WALLPAPER
:
811 aBackgroundComponent
.aBounds
,
812 aBackgroundComponent
.aBgColor
,
813 static_cast<const MetaWallpaperAction
*>(pCurrAct
)->GetRect(),
814 *aMapModeVDev
.get()) )
815 bStillBackground
=false; // incomplete occlusion of background
817 nLastBgAction
=nActionNum
; // this _is_ background
822 if( ImplIsNotTransparent( *pCurrAct
,
823 *aMapModeVDev
.get() ) )
824 bStillBackground
=false; // non-transparent action, possibly
827 // extend current bounds (next uniform action
828 // needs to fully cover this area)
829 aBackgroundComponent
.aBounds
.Union(
830 ImplCalcActionBounds(*pCurrAct
, *aMapModeVDev
.get()) );
835 // execute action to get correct MapModes etc.
836 pCurrAct
->Execute( aMapModeVDev
.get() );
838 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction();
842 // clean up aMapModeVDev
843 sal_uInt32 nCount
= aMapModeVDev
->GetGCStackDepth();
847 ConnectedComponentsList aCCList
; // list containing distinct sets of connected components as elements.
849 // fast-forward until one after the last background action
850 // (need to reconstruct map mode vdev state)
852 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction();
853 while( pCurrAct
&& nActionNum
<=nLastBgAction
)
855 // up to and including last ink-generating background
856 // action go to background component
857 aBackgroundComponent
.aComponentList
.push_back(
859 pCurrAct
, nActionNum
) );
861 // execute action to get correct MapModes etc.
862 pCurrAct
->Execute( aMapModeVDev
.get() );
863 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction();
867 // STAGE 2: Generate connected components list
869 // iterate over all actions (start where background action
873 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
875 // execute action to get correct MapModes etc.
876 pCurrAct
->Execute( aMapModeVDev
.get() );
878 // cache bounds of current action
879 const Rectangle
aBBCurrAct( ImplCalcActionBounds(*pCurrAct
, *aMapModeVDev
.get()) );
881 // accumulate collected bounds here, initialize with current action
882 Rectangle
aTotalBounds( aBBCurrAct
); // thus,
883 // aTotalComponents.aBounds
887 // non-output-generating
889 bool bTreatSpecial( false );
890 ConnectedComponents aTotalComponents
;
892 // STAGE 2.1: Search for intersecting cc entries
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
901 // #107169# Wholly transparent objects need
902 // not be considered for connected components,
903 // too. Just put each of them into a separate
905 aTotalComponents
.bIsFullyTransparent
= !ImplIsNotTransparent(*pCurrAct
, *aMapModeVDev
.get());
907 if( !aBBCurrAct
.IsEmpty() &&
908 !aTotalComponents
.bIsFullyTransparent
)
910 if( !aBackgroundComponent
.aComponentList
.empty() &&
911 !aBackgroundComponent
.aBounds
.IsInside(aTotalBounds
) )
913 // it seems the background is not large enough. to
914 // be on the safe side, combine with this component.
915 aTotalBounds
.Union( aBackgroundComponent
.aBounds
);
917 // extract all aCurr actions to aTotalComponents
918 aTotalComponents
.aComponentList
.splice( aTotalComponents
.aComponentList
.end(),
919 aBackgroundComponent
.aComponentList
);
921 if( aBackgroundComponent
.bIsSpecial
)
922 bTreatSpecial
= true;
925 ConnectedComponentsList::iterator aCurrCC
;
926 const ConnectedComponentsList::iterator
aLastCC( aCCList
.end() );
927 bool bSomeComponentsChanged
;
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
938 // only loop here if 'intersects' branch below was hit
939 bSomeComponentsChanged
= false;
941 // iterate over all current members of aCCList
942 for( aCurrCC
=aCCList
.begin(); aCurrCC
!= aLastCC
; )
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.
949 // #107169# Wholly transparent objects need
950 // not be considered for connected components,
951 // too. Just put each of them into a separate
953 if( !aCurrCC
->aBounds
.IsEmpty() &&
954 !aCurrCC
->bIsFullyTransparent
&&
955 aCurrCC
->aBounds
.IsOver( aTotalBounds
) )
957 // union the intersecting aCCList element into aTotalComponents
959 // calc union bounding box
960 aTotalBounds
.Union( aCurrCC
->aBounds
);
962 // extract all aCurr actions to aTotalComponents
963 aTotalComponents
.aComponentList
.splice( aTotalComponents
.aComponentList
.end(),
964 aCurrCC
->aComponentList
);
966 if( aCurrCC
->bIsSpecial
)
967 bTreatSpecial
= true;
969 // remove and delete aCurrCC element from list (we've now merged its content)
970 aCurrCC
= aCCList
.erase( aCurrCC
);
972 // at least one component changed, need to rescan everything
973 bSomeComponentsChanged
= true;
981 while( bSomeComponentsChanged
);
984 // STAGE 2.2: Determine special state for cc element
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.
1002 // prev component(s) special -> this one, too
1003 aTotalComponents
.bIsSpecial
= true;
1005 else if( !IsTransparentAction( *pCurrAct
) )
1007 // added action and none of prev components special ->
1008 // this one normal, too
1009 aTotalComponents
.bIsSpecial
= false;
1013 // added action is special and none of prev components
1014 // special -> do the detailed tests
1016 // can the action handle transparency correctly
1017 // (i.e. when painted on white background, does the
1018 // action still look correct)?
1019 if( !DoesActionHandleTransparency( *pCurrAct
) )
1021 // no, action cannot handle its transparency on
1022 // a printer device, render to bitmap
1023 aTotalComponents
.bIsSpecial
= true;
1027 // yes, action can handle its transparency, so
1028 // check whether we're on white background
1029 if( aTotalComponents
.aComponentList
.empty() )
1031 // nothing between pCurrAct and page
1032 // background -> don't be special
1033 aTotalComponents
.bIsSpecial
= false;
1037 // #107169# Fixes above 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.
1043 // there are non-transparent objects between
1044 // pCurrAct and the empty sheet of paper -> be
1046 aTotalComponents
.bIsSpecial
= true;
1051 // STAGE 2.3: Add newly generated CC list element
1053 // set new bounds and add action to list
1054 aTotalComponents
.aBounds
= aTotalBounds
;
1055 aTotalComponents
.aComponentList
.push_back(
1057 pCurrAct
, nActionNum
) );
1059 // add aTotalComponents as a new entry to aCCList
1060 aCCList
.push_back( aTotalComponents
);
1062 DBG_ASSERT( !aTotalComponents
.aComponentList
.empty(),
1063 "Printer::GetPreparedMetaFile empty component" );
1064 DBG_ASSERT( !aTotalComponents
.aBounds
.IsEmpty() || (aTotalComponents
.aComponentList
.size() == 1),
1065 "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
1066 DBG_ASSERT( !aTotalComponents
.bIsFullyTransparent
|| (aTotalComponents
.aComponentList
.size() == 1),
1067 "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
1070 // well now, we've got the list of disjunct connected
1071 // components. Now we've got to create a map, which contains
1072 // the corresponding aCCList element for every
1073 // metaaction. Later on, we always process the complete
1074 // metafile for each bitmap to be generated, but switch on
1075 // output only for actions contained in the then current
1076 // aCCList element. This ensures correct mapmode and attribute
1077 // settings for all cases.
1079 // maps mtf actions to CC list entries
1080 ::std::vector
< const ConnectedComponents
* > aCCList_MemberMap( rInMtf
.GetActionSize() );
1082 // iterate over all aCCList members and their contained metaactions
1083 ConnectedComponentsList::iterator
aCurr( aCCList
.begin() );
1084 const ConnectedComponentsList::iterator
aLast( aCCList
.end() );
1085 for( ; aCurr
!= aLast
; ++aCurr
)
1087 ComponentList::iterator
aCurrentAction( aCurr
->aComponentList
.begin() );
1088 const ComponentList::iterator
aLastAction( aCurr
->aComponentList
.end() );
1089 for( ; aCurrentAction
!= aLastAction
; ++aCurrentAction
)
1091 // set pointer to aCCList element for corresponding index
1092 aCCList_MemberMap
[ aCurrentAction
->second
] = &(*aCurr
);
1096 // STAGE 3.1: Output background mtf actions (if there are any)
1098 ComponentList::iterator
aCurrAct( aBackgroundComponent
.aComponentList
.begin() );
1099 const ComponentList::iterator
aLastAct( aBackgroundComponent
.aComponentList
.end() );
1100 for( ; aCurrAct
!= aLastAct
; ++aCurrAct
)
1102 // simply add this action (above, we inserted the actions
1103 // starting at index 0 up to and including nLastBgAction)
1104 rOutMtf
.AddAction( ( aCurrAct
->first
->Duplicate(), aCurrAct
->first
) );
1107 // STAGE 3.2: Generate banded bitmaps for special regions
1110 Size
aTmpSize( GetOutputSizePixel() );
1113 aTmpSize
= mpPDFWriter
->getCurPageSize();
1114 aTmpSize
= LogicToPixel( aTmpSize
, MapMode( MAP_POINT
) );
1116 // also add error code to PDFWriter
1117 mpPDFWriter
->insertError( vcl::PDFWriter::Warning_Transparency_Converted
);
1119 else if( meOutDevType
== OUTDEV_PRINTER
)
1121 Printer
* pThis
= dynamic_cast<Printer
*>(this);
1122 aPageOffset
= pThis
->GetPageOffsetPixel();
1123 aPageOffset
= Point( 0, 0 ) - aPageOffset
;
1124 aTmpSize
= pThis
->GetPaperSizePixel();
1126 const Rectangle
aOutputRect( aPageOffset
, aTmpSize
);
1127 bool bTiling
= dynamic_cast<Printer
*>(this) != nullptr;
1129 // iterate over all aCCList members and generate bitmaps for the special ones
1130 for( aCurr
= aCCList
.begin(); aCurr
!= aLast
; ++aCurr
)
1132 if( aCurr
->bIsSpecial
)
1134 Rectangle
aBoundRect( aCurr
->aBounds
);
1135 aBoundRect
.Intersection( aOutputRect
);
1137 const double fBmpArea( (double) aBoundRect
.GetWidth() * aBoundRect
.GetHeight() );
1138 const double fOutArea( (double) aOutputRect
.GetWidth() * aOutputRect
.GetHeight() );
1140 // check if output doesn't exceed given size
1141 if( bReduceTransparency
&& bTransparencyAutoMode
&& ( fBmpArea
> ( 0.25 * fOutArea
) ) )
1143 // output normally. Therefore, we simply clear the
1144 // special attribute, as everything non-special is
1145 // copied to rOutMtf further below.
1146 aCurr
->bIsSpecial
= false;
1150 // create new bitmap action first
1151 if( aBoundRect
.GetWidth() && aBoundRect
.GetHeight() )
1153 Point
aDstPtPix( aBoundRect
.TopLeft() );
1156 ScopedVclPtrInstance
<VirtualDevice
> aMapVDev
; // here, we record only mapmode information
1157 aMapVDev
->EnableOutput(false);
1159 ScopedVclPtrInstance
<VirtualDevice
> aPaintVDev
; // into this one, we render.
1160 aPaintVDev
->SetBackground( aBackgroundComponent
.aBgColor
);
1162 rOutMtf
.AddAction( new MetaPushAction( PushFlags::MAPMODE
) );
1163 rOutMtf
.AddAction( new MetaMapModeAction() );
1165 aPaintVDev
->SetDrawMode( GetDrawMode() );
1167 while( aDstPtPix
.Y() <= aBoundRect
.Bottom() )
1169 aDstPtPix
.X() = aBoundRect
.Left();
1170 aDstSzPix
= bTiling
? Size( MAX_TILE_WIDTH
, MAX_TILE_HEIGHT
) : aBoundRect
.GetSize();
1172 if( ( aDstPtPix
.Y() + aDstSzPix
.Height() - 1L ) > aBoundRect
.Bottom() )
1173 aDstSzPix
.Height() = aBoundRect
.Bottom() - aDstPtPix
.Y() + 1L;
1175 while( aDstPtPix
.X() <= aBoundRect
.Right() )
1177 if( ( aDstPtPix
.X() + aDstSzPix
.Width() - 1L ) > aBoundRect
.Right() )
1178 aDstSzPix
.Width() = aBoundRect
.Right() - aDstPtPix
.X() + 1L;
1180 if( !Rectangle( aDstPtPix
, aDstSzPix
).Intersection( aBoundRect
).IsEmpty() &&
1181 aPaintVDev
->SetOutputSizePixel( aDstSzPix
) )
1186 aMapVDev
->mnDPIX
= aPaintVDev
->mnDPIX
= mnDPIX
;
1187 aMapVDev
->mnDPIY
= aPaintVDev
->mnDPIY
= mnDPIY
;
1189 aPaintVDev
->EnableOutput(false);
1191 // iterate over all actions
1192 for( pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction(), nActionNum
=0;
1194 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
1196 // enable output only for
1197 // actions that are members of
1198 // the current aCCList element
1200 if( aCCList_MemberMap
[nActionNum
] == &(*aCurr
) )
1201 aPaintVDev
->EnableOutput();
1203 // but process every action
1204 const MetaActionType
nType( pCurrAct
->GetType() );
1206 if( MetaActionType::MAPMODE
== nType
)
1208 pCurrAct
->Execute( aMapVDev
.get() );
1210 MapMode
aMtfMap( aMapVDev
->GetMapMode() );
1211 const Point
aNewOrg( aMapVDev
->PixelToLogic( aDstPtPix
) );
1213 aMtfMap
.SetOrigin( Point( -aNewOrg
.X(), -aNewOrg
.Y() ) );
1214 aPaintVDev
->SetMapMode( aMtfMap
);
1216 else if( ( MetaActionType::PUSH
== nType
) || ( MetaActionType::POP
) == nType
)
1218 pCurrAct
->Execute( aMapVDev
.get() );
1219 pCurrAct
->Execute( aPaintVDev
.get() );
1221 else if( MetaActionType::GRADIENT
== nType
)
1223 MetaGradientAction
* pGradientAction
= static_cast<MetaGradientAction
*>(pCurrAct
);
1224 Printer
* pPrinter
= dynamic_cast< Printer
* >(this);
1226 pPrinter
->DrawGradientEx( aPaintVDev
.get(), pGradientAction
->GetRect(), pGradientAction
->GetGradient() );
1228 DrawGradient( pGradientAction
->GetRect(), pGradientAction
->GetGradient() );
1232 pCurrAct
->Execute( aPaintVDev
.get() );
1235 if( !( nActionNum
% 8 ) )
1236 Application::Reschedule();
1239 const bool bOldMap
= mbMap
;
1240 mbMap
= aPaintVDev
->mbMap
= false;
1242 Bitmap
aBandBmp( aPaintVDev
->GetBitmap( Point(), aDstSzPix
) );
1244 // scale down bitmap, if requested
1245 if( bDownsampleBitmaps
)
1247 aBandBmp
= GetDownsampledBitmap( aDstSzPix
,
1248 Point(), aBandBmp
.GetSizePixel(),
1249 aBandBmp
, nMaxBmpDPIX
, nMaxBmpDPIY
);
1252 rOutMtf
.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
1253 rOutMtf
.AddAction( new MetaBmpScaleAction( aDstPtPix
, aDstSzPix
, aBandBmp
) );
1254 rOutMtf
.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
1256 aPaintVDev
->mbMap
= true;
1262 // overlapping bands to avoid missing lines (e.g. PostScript)
1263 aDstPtPix
.X() += aDstSzPix
.Width();
1266 // overlapping bands to avoid missing lines (e.g. PostScript)
1267 aDstPtPix
.Y() += aDstSzPix
.Height();
1270 rOutMtf
.AddAction( new MetaPopAction() );
1276 // clean up aMapModeVDev
1277 nCount
= aMapModeVDev
->GetGCStackDepth();
1279 aMapModeVDev
->Pop();
1281 // STAGE 4: Copy actions to output metafile
1283 // iterate over all actions and duplicate the ones not in a
1284 // special aCCList member into rOutMtf
1285 for( pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction(), nActionNum
=0;
1287 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
1289 const ConnectedComponents
* pCurrAssociatedComponent
= aCCList_MemberMap
[nActionNum
];
1291 // NOTE: This relies on the fact that map-mode or draw
1292 // mode changing actions are solitary aCCList elements and
1293 // have empty bounding boxes, see comment on stage 2.1
1295 if( pCurrAssociatedComponent
&&
1296 (pCurrAssociatedComponent
->aBounds
.IsEmpty() ||
1297 !pCurrAssociatedComponent
->bIsSpecial
) )
1299 // #107169# Treat transparent bitmaps special, if they
1300 // are the first (or sole) action in their bounds
1301 // list. Note that we previously ensured that no
1302 // fully-transparent objects are before us here.
1303 if( DoesActionHandleTransparency( *pCurrAct
) &&
1304 pCurrAssociatedComponent
->aComponentList
.begin()->first
== pCurrAct
)
1306 // convert actions, where masked-out parts are of
1307 // given background color
1308 ImplConvertTransparentAction(rOutMtf
,
1310 *aMapModeVDev
.get(),
1311 aBackgroundComponent
.aBgColor
);
1315 // simply add this action
1316 rOutMtf
.AddAction( ( pCurrAct
->Duplicate(), pCurrAct
) );
1319 pCurrAct
->Execute(aMapModeVDev
.get());
1323 rOutMtf
.SetPrefMapMode( rInMtf
.GetPrefMapMode() );
1324 rOutMtf
.SetPrefSize( rInMtf
.GetPrefSize() );
1326 #if OSL_DEBUG_LEVEL > 1
1327 // iterate over all aCCList members and generate rectangles for the bounding boxes
1328 rOutMtf
.AddAction( new MetaFillColorAction( COL_WHITE
, false ) );
1329 for( aCurr
= aCCList
.begin(); aCurr
!= aLast
; ++aCurr
)
1331 if( aCurr
->bIsSpecial
)
1332 rOutMtf
.AddAction( new MetaLineColorAction( COL_RED
, true) );
1334 rOutMtf
.AddAction( new MetaLineColorAction( COL_BLUE
, true) );
1336 rOutMtf
.AddAction( new MetaRectAction( aMapModeVDev
->PixelToLogic( aCurr
->aBounds
) ) );
1340 return bTransparent
;
1343 void Printer::DrawGradientEx( OutputDevice
* pOut
, const Rectangle
& rRect
, const Gradient
& rGradient
)
1345 const PrinterOptions
& rPrinterOptions
= GetPrinterOptions();
1347 if( rPrinterOptions
.IsReduceGradients() )
1349 if( PRINTER_GRADIENT_STRIPES
== rPrinterOptions
.GetReducedGradientMode() )
1351 if( !rGradient
.GetSteps() || ( rGradient
.GetSteps() > rPrinterOptions
.GetReducedGradientStepCount() ) )
1353 Gradient
aNewGradient( rGradient
);
1355 aNewGradient
.SetSteps( rPrinterOptions
.GetReducedGradientStepCount() );
1356 pOut
->DrawGradient( rRect
, aNewGradient
);
1359 pOut
->DrawGradient( rRect
, rGradient
);
1363 const Color
& rStartColor
= rGradient
.GetStartColor();
1364 const Color
& rEndColor
= rGradient
.GetEndColor();
1365 const long nR
= ( ( (long) rStartColor
.GetRed() * rGradient
.GetStartIntensity() ) / 100L +
1366 ( (long) rEndColor
.GetRed() * rGradient
.GetEndIntensity() ) / 100L ) >> 1;
1367 const long nG
= ( ( (long) rStartColor
.GetGreen() * rGradient
.GetStartIntensity() ) / 100L +
1368 ( (long) rEndColor
.GetGreen() * rGradient
.GetEndIntensity() ) / 100L ) >> 1;
1369 const long nB
= ( ( (long) rStartColor
.GetBlue() * rGradient
.GetStartIntensity() ) / 100L +
1370 ( (long) rEndColor
.GetBlue() * rGradient
.GetEndIntensity() ) / 100L ) >> 1;
1371 const Color
aColor( (sal_uInt8
) nR
, (sal_uInt8
) nG
, (sal_uInt8
) nB
);
1373 pOut
->Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
1374 pOut
->SetLineColor( aColor
);
1375 pOut
->SetFillColor( aColor
);
1376 pOut
->DrawRect( rRect
);
1381 pOut
->DrawGradient( rRect
, rGradient
);
1384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */