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>
30 #include <vcl/virdev.hxx>
31 #include <vcl/metaact.hxx>
32 #include <vcl/gdimtf.hxx>
33 #include <vcl/print.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/bitmapaccess.hxx>
39 #include "pdfwriter_impl.hxx"
41 #define MAX_TILE_WIDTH 1024
42 #define MAX_TILE_HEIGHT 1024
44 typedef ::std::pair
< MetaAction
*, int > Component
; // MetaAction plus index in metafile
46 typedef ::std::list
< Component
> ComponentList
;
48 // List of (intersecting) actions, plus overall bounds
49 struct ConnectedComponents
51 ConnectedComponents() :
56 bIsFullyTransparent(false)
59 ComponentList aComponentList
;
60 tools::Rectangle aBounds
;
63 bool bIsFullyTransparent
;
66 typedef ::std::list
< ConnectedComponents
> ConnectedComponentsList
;
70 /** \#i10613# Extracted from Printer::GetPreparedMetaFile. Returns true
71 if given action requires special transparency handling
73 bool IsTransparentAction( const MetaAction
& rAct
)
75 switch( rAct
.GetType() )
77 case MetaActionType::Transparent
:
80 case MetaActionType::FLOATTRANSPARENT
:
83 case MetaActionType::BMPEX
:
84 return static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx().IsTransparent();
86 case MetaActionType::BMPEXSCALE
:
87 return static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx().IsTransparent();
89 case MetaActionType::BMPEXSCALEPART
:
90 return static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetBitmapEx().IsTransparent();
98 /** Determines whether the action can handle transparency correctly
99 (i.e. when painted on white background, does the action still look
102 bool DoesActionHandleTransparency( const MetaAction
& rAct
)
104 // MetaActionType::FLOATTRANSPARENT can contain a whole metafile,
105 // which is to be rendered with the given transparent gradient. We
106 // currently cannot emulate transparent painting on a white
107 // background reliably.
109 // the remainder can handle printing itself correctly on a uniform
111 switch( rAct
.GetType() )
113 case MetaActionType::Transparent
:
114 case MetaActionType::BMPEX
:
115 case MetaActionType::BMPEXSCALE
:
116 case MetaActionType::BMPEXSCALEPART
:
124 /** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
125 yes, return true and update o_rBgColor
127 bool checkRect( tools::Rectangle
& io_rPrevRect
,
129 const tools::Rectangle
& rCurrRect
,
130 OutputDevice
& rMapModeVDev
)
132 // shape needs to fully cover previous content, and have uniform
135 rMapModeVDev
.LogicToPixel(rCurrRect
).IsInside(io_rPrevRect
) &&
136 rMapModeVDev
.IsFillColor() );
140 io_rPrevRect
= rCurrRect
;
141 o_rBgColor
= rMapModeVDev
.GetFillColor();
147 /** #107169# Convert BitmapEx to Bitmap with appropriately blended
148 color. Convert MetaTransparentAction to plain polygon,
149 appropriately colored
152 Add converted actions to this metafile
154 void ImplConvertTransparentAction( GDIMetaFile
& o_rMtf
,
155 const MetaAction
& rAct
,
156 const OutputDevice
& rStateOutDev
,
159 if( rAct
.GetType() == MetaActionType::Transparent
)
161 const MetaTransparentAction
* pTransAct
= static_cast<const MetaTransparentAction
*>(&rAct
);
162 sal_uInt16
nTransparency( pTransAct
->GetTransparence() );
164 // #i10613# Respect transparency for draw color
167 o_rMtf
.AddAction( new MetaPushAction( PushFlags::LINECOLOR
|PushFlags::FILLCOLOR
) );
169 // assume white background for alpha blending
170 Color
aLineColor( rStateOutDev
.GetLineColor() );
171 aLineColor
.SetRed( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aLineColor
.GetRed()) / 100 ) );
172 aLineColor
.SetGreen( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aLineColor
.GetGreen()) / 100 ) );
173 aLineColor
.SetBlue( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aLineColor
.GetBlue()) / 100 ) );
174 o_rMtf
.AddAction( new MetaLineColorAction(aLineColor
, true) );
176 Color
aFillColor( rStateOutDev
.GetFillColor() );
177 aFillColor
.SetRed( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aFillColor
.GetRed()) / 100 ) );
178 aFillColor
.SetGreen( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aFillColor
.GetGreen()) / 100 ) );
179 aFillColor
.SetBlue( static_cast<sal_uInt8
>( (255*nTransparency
+ (100 - nTransparency
)*aFillColor
.GetBlue()) / 100 ) );
180 o_rMtf
.AddAction( new MetaFillColorAction(aFillColor
, true) );
183 o_rMtf
.AddAction( new MetaPolyPolygonAction(pTransAct
->GetPolyPolygon()) );
186 o_rMtf
.AddAction( new MetaPopAction() );
192 switch( rAct
.GetType() )
194 case MetaActionType::BMPEX
:
195 aBmpEx
= static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx();
198 case MetaActionType::BMPEXSCALE
:
199 aBmpEx
= static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx();
202 case MetaActionType::BMPEXSCALEPART
:
203 aBmpEx
= static_cast<const MetaBmpExScaleAction
&>(rAct
).GetBitmapEx();
206 case MetaActionType::Transparent
:
209 OSL_FAIL("Printer::GetPreparedMetafile impossible state reached");
213 Bitmap
aBmp( aBmpEx
.GetBitmap() );
214 if( !aBmpEx
.IsAlpha() )
217 Bitmap::ScopedReadAccess
pRA(aBmp
);
220 return; // what else should I do?
222 Color
aActualColor( aBgColor
);
224 if( pRA
->HasPalette() )
225 aActualColor
= pRA
->GetBestPaletteColor( aBgColor
).operator Color();
229 // did we get true white?
230 if( aActualColor
.GetColorError( aBgColor
) )
232 // no, create truecolor bitmap, then
233 aBmp
.Convert( BmpConversion::N24Bit
);
235 // fill masked out areas white
236 aBmp
.Replace( aBmpEx
.GetMask(), aBgColor
);
240 // fill masked out areas white
241 aBmp
.Replace( aBmpEx
.GetMask(), aActualColor
);
246 // blend with alpha channel
247 aBmp
.Convert( BmpConversion::N24Bit
);
248 aBmp
.Blend(aBmpEx
.GetAlpha(),aBgColor
);
251 // add corresponding action
252 switch( rAct
.GetType() )
254 case MetaActionType::BMPEX
:
255 o_rMtf
.AddAction( new MetaBmpAction(
256 static_cast<const MetaBmpExAction
&>(rAct
).GetPoint(),
259 case MetaActionType::BMPEXSCALE
:
260 o_rMtf
.AddAction( new MetaBmpScaleAction(
261 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetPoint(),
262 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetSize(),
265 case MetaActionType::BMPEXSCALEPART
:
266 o_rMtf
.AddAction( new MetaBmpScalePartAction(
267 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestPoint(),
268 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestSize(),
269 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetSrcPoint(),
270 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetSrcSize(),
274 OSL_FAIL("Unexpected case");
280 // #i10613# Extracted from ImplCheckRect::ImplCreate
281 // Returns true, if given action creates visible (i.e. non-transparent) output
282 bool ImplIsNotTransparent( const MetaAction
& rAct
, const OutputDevice
& rOut
)
284 const bool bLineTransparency( !rOut
.IsLineColor() || rOut
.GetLineColor().GetTransparency() == 255 );
285 const bool bFillTransparency( !rOut
.IsFillColor() || rOut
.GetFillColor().GetTransparency() == 255 );
288 switch( rAct
.GetType() )
290 case MetaActionType::POINT
:
291 if( !bLineTransparency
)
295 case MetaActionType::LINE
:
296 if( !bLineTransparency
)
300 case MetaActionType::RECT
:
301 if( !bLineTransparency
|| !bFillTransparency
)
305 case MetaActionType::ROUNDRECT
:
306 if( !bLineTransparency
|| !bFillTransparency
)
310 case MetaActionType::ELLIPSE
:
311 if( !bLineTransparency
|| !bFillTransparency
)
315 case MetaActionType::ARC
:
316 if( !bLineTransparency
|| !bFillTransparency
)
320 case MetaActionType::PIE
:
321 if( !bLineTransparency
|| !bFillTransparency
)
325 case MetaActionType::CHORD
:
326 if( !bLineTransparency
|| !bFillTransparency
)
330 case MetaActionType::POLYLINE
:
331 if( !bLineTransparency
)
335 case MetaActionType::POLYGON
:
336 if( !bLineTransparency
|| !bFillTransparency
)
340 case MetaActionType::POLYPOLYGON
:
341 if( !bLineTransparency
|| !bFillTransparency
)
345 case MetaActionType::TEXT
:
347 const MetaTextAction
& rTextAct
= static_cast<const MetaTextAction
&>(rAct
);
348 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
349 if (!aString
.isEmpty())
354 case MetaActionType::TEXTARRAY
:
356 const MetaTextArrayAction
& rTextAct
= static_cast<const MetaTextArrayAction
&>(rAct
);
357 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
358 if (!aString
.isEmpty())
363 case MetaActionType::PIXEL
:
364 case MetaActionType::BMP
:
365 case MetaActionType::BMPSCALE
:
366 case MetaActionType::BMPSCALEPART
:
367 case MetaActionType::BMPEX
:
368 case MetaActionType::BMPEXSCALE
:
369 case MetaActionType::BMPEXSCALEPART
:
370 case MetaActionType::MASK
:
371 case MetaActionType::MASKSCALE
:
372 case MetaActionType::MASKSCALEPART
:
373 case MetaActionType::GRADIENT
:
374 case MetaActionType::GRADIENTEX
:
375 case MetaActionType::HATCH
:
376 case MetaActionType::WALLPAPER
:
377 case MetaActionType::Transparent
:
378 case MetaActionType::FLOATTRANSPARENT
:
379 case MetaActionType::EPS
:
380 case MetaActionType::TEXTRECT
:
381 case MetaActionType::STRETCHTEXT
:
382 case MetaActionType::TEXTLINE
:
383 // all other actions: generate non-transparent output
394 // #i10613# Extracted from ImplCheckRect::ImplCreate
395 tools::Rectangle
ImplCalcActionBounds( const MetaAction
& rAct
, const OutputDevice
& rOut
)
397 tools::Rectangle aActionBounds
;
399 switch( rAct
.GetType() )
401 case MetaActionType::PIXEL
:
402 aActionBounds
= tools::Rectangle( static_cast<const MetaPixelAction
&>(rAct
).GetPoint(), Size( 1, 1 ) );
405 case MetaActionType::POINT
:
406 aActionBounds
= tools::Rectangle( static_cast<const MetaPointAction
&>(rAct
).GetPoint(), Size( 1, 1 ) );
409 case MetaActionType::LINE
:
411 const MetaLineAction
& rMetaLineAction
= static_cast<const MetaLineAction
&>(rAct
);
412 aActionBounds
= tools::Rectangle( rMetaLineAction
.GetStartPoint(), rMetaLineAction
.GetEndPoint() );
413 aActionBounds
.Justify();
414 const long nLineWidth(rMetaLineAction
.GetLineInfo().GetWidth());
417 const long nHalfLineWidth((nLineWidth
+ 1) / 2);
418 aActionBounds
.Left() -= nHalfLineWidth
;
419 aActionBounds
.Top() -= nHalfLineWidth
;
420 aActionBounds
.Right() += nHalfLineWidth
;
421 aActionBounds
.Bottom() += nHalfLineWidth
;
426 case MetaActionType::RECT
:
427 aActionBounds
= static_cast<const MetaRectAction
&>(rAct
).GetRect();
430 case MetaActionType::ROUNDRECT
:
431 aActionBounds
= tools::Polygon( static_cast<const MetaRoundRectAction
&>(rAct
).GetRect(),
432 static_cast<const MetaRoundRectAction
&>(rAct
).GetHorzRound(),
433 static_cast<const MetaRoundRectAction
&>(rAct
).GetVertRound() ).GetBoundRect();
436 case MetaActionType::ELLIPSE
:
438 const tools::Rectangle
& rRect
= static_cast<const MetaEllipseAction
&>(rAct
).GetRect();
439 aActionBounds
= tools::Polygon( rRect
.Center(),
440 rRect
.GetWidth() >> 1,
441 rRect
.GetHeight() >> 1 ).GetBoundRect();
445 case MetaActionType::ARC
:
446 aActionBounds
= tools::Polygon( static_cast<const MetaArcAction
&>(rAct
).GetRect(),
447 static_cast<const MetaArcAction
&>(rAct
).GetStartPoint(),
448 static_cast<const MetaArcAction
&>(rAct
).GetEndPoint(), PolyStyle::Arc
).GetBoundRect();
451 case MetaActionType::PIE
:
452 aActionBounds
= tools::Polygon( static_cast<const MetaPieAction
&>(rAct
).GetRect(),
453 static_cast<const MetaPieAction
&>(rAct
).GetStartPoint(),
454 static_cast<const MetaPieAction
&>(rAct
).GetEndPoint(), PolyStyle::Pie
).GetBoundRect();
457 case MetaActionType::CHORD
:
458 aActionBounds
= tools::Polygon( static_cast<const MetaChordAction
&>(rAct
).GetRect(),
459 static_cast<const MetaChordAction
&>(rAct
).GetStartPoint(),
460 static_cast<const MetaChordAction
&>(rAct
).GetEndPoint(), PolyStyle::Chord
).GetBoundRect();
463 case MetaActionType::POLYLINE
:
465 const MetaPolyLineAction
& rMetaPolyLineAction
= static_cast<const MetaPolyLineAction
&>(rAct
);
466 aActionBounds
= rMetaPolyLineAction
.GetPolygon().GetBoundRect();
467 const long nLineWidth(rMetaPolyLineAction
.GetLineInfo().GetWidth());
470 const long nHalfLineWidth((nLineWidth
+ 1) / 2);
471 aActionBounds
.Left() -= nHalfLineWidth
;
472 aActionBounds
.Top() -= nHalfLineWidth
;
473 aActionBounds
.Right() += nHalfLineWidth
;
474 aActionBounds
.Bottom() += nHalfLineWidth
;
479 case MetaActionType::POLYGON
:
480 aActionBounds
= static_cast<const MetaPolygonAction
&>(rAct
).GetPolygon().GetBoundRect();
483 case MetaActionType::POLYPOLYGON
:
484 aActionBounds
= static_cast<const MetaPolyPolygonAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
487 case MetaActionType::BMP
:
488 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpAction
&>(rAct
).GetPoint(),
489 rOut
.PixelToLogic( static_cast<const MetaBmpAction
&>(rAct
).GetBitmap().GetSizePixel() ) );
492 case MetaActionType::BMPSCALE
:
493 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpScaleAction
&>(rAct
).GetPoint(),
494 static_cast<const MetaBmpScaleAction
&>(rAct
).GetSize() );
497 case MetaActionType::BMPSCALEPART
:
498 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpScalePartAction
&>(rAct
).GetDestPoint(),
499 static_cast<const MetaBmpScalePartAction
&>(rAct
).GetDestSize() );
502 case MetaActionType::BMPEX
:
503 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpExAction
&>(rAct
).GetPoint(),
504 rOut
.PixelToLogic( static_cast<const MetaBmpExAction
&>(rAct
).GetBitmapEx().GetSizePixel() ) );
507 case MetaActionType::BMPEXSCALE
:
508 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpExScaleAction
&>(rAct
).GetPoint(),
509 static_cast<const MetaBmpExScaleAction
&>(rAct
).GetSize() );
512 case MetaActionType::BMPEXSCALEPART
:
513 aActionBounds
= tools::Rectangle( static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestPoint(),
514 static_cast<const MetaBmpExScalePartAction
&>(rAct
).GetDestSize() );
517 case MetaActionType::MASK
:
518 aActionBounds
= tools::Rectangle( static_cast<const MetaMaskAction
&>(rAct
).GetPoint(),
519 rOut
.PixelToLogic( static_cast<const MetaMaskAction
&>(rAct
).GetBitmap().GetSizePixel() ) );
522 case MetaActionType::MASKSCALE
:
523 aActionBounds
= tools::Rectangle( static_cast<const MetaMaskScaleAction
&>(rAct
).GetPoint(),
524 static_cast<const MetaMaskScaleAction
&>(rAct
).GetSize() );
527 case MetaActionType::MASKSCALEPART
:
528 aActionBounds
= tools::Rectangle( static_cast<const MetaMaskScalePartAction
&>(rAct
).GetDestPoint(),
529 static_cast<const MetaMaskScalePartAction
&>(rAct
).GetDestSize() );
532 case MetaActionType::GRADIENT
:
533 aActionBounds
= static_cast<const MetaGradientAction
&>(rAct
).GetRect();
536 case MetaActionType::GRADIENTEX
:
537 aActionBounds
= static_cast<const MetaGradientExAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
540 case MetaActionType::HATCH
:
541 aActionBounds
= static_cast<const MetaHatchAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
544 case MetaActionType::WALLPAPER
:
545 aActionBounds
= static_cast<const MetaWallpaperAction
&>(rAct
).GetRect();
548 case MetaActionType::Transparent
:
549 aActionBounds
= static_cast<const MetaTransparentAction
&>(rAct
).GetPolyPolygon().GetBoundRect();
552 case MetaActionType::FLOATTRANSPARENT
:
553 aActionBounds
= tools::Rectangle( static_cast<const MetaFloatTransparentAction
&>(rAct
).GetPoint(),
554 static_cast<const MetaFloatTransparentAction
&>(rAct
).GetSize() );
557 case MetaActionType::EPS
:
558 aActionBounds
= tools::Rectangle( static_cast<const MetaEPSAction
&>(rAct
).GetPoint(),
559 static_cast<const MetaEPSAction
&>(rAct
).GetSize() );
562 case MetaActionType::TEXT
:
564 const MetaTextAction
& rTextAct
= static_cast<const MetaTextAction
&>(rAct
);
565 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
567 if (!aString
.isEmpty())
569 const Point
aPtLog( rTextAct
.GetPoint() );
571 // #105987# Use API method instead of Impl* methods
572 // #107490# Set base parameter equal to index parameter
573 rOut
.GetTextBoundRect( aActionBounds
, rTextAct
.GetText(), rTextAct
.GetIndex(),
574 rTextAct
.GetIndex(), rTextAct
.GetLen() );
575 aActionBounds
.Move( aPtLog
.X(), aPtLog
.Y() );
580 case MetaActionType::TEXTARRAY
:
582 const MetaTextArrayAction
& rTextAct
= static_cast<const MetaTextArrayAction
&>(rAct
);
583 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
585 if( !aString
.isEmpty() )
587 // #105987# ImplLayout takes everything in logical coordinates
588 SalLayout
* pSalLayout
= rOut
.ImplLayout( rTextAct
.GetText(), rTextAct
.GetIndex(),
589 rTextAct
.GetLen(), rTextAct
.GetPoint(),
590 0, rTextAct
.GetDXArray() );
593 tools::Rectangle
aBoundRect( const_cast<OutputDevice
&>(rOut
).ImplGetTextBoundRect( *pSalLayout
) );
594 aActionBounds
= rOut
.PixelToLogic( aBoundRect
);
595 pSalLayout
->Release();
601 case MetaActionType::TEXTRECT
:
602 aActionBounds
= static_cast<const MetaTextRectAction
&>(rAct
).GetRect();
605 case MetaActionType::STRETCHTEXT
:
607 const MetaStretchTextAction
& rTextAct
= static_cast<const MetaStretchTextAction
&>(rAct
);
608 const OUString
aString( rTextAct
.GetText().copy(rTextAct
.GetIndex(), rTextAct
.GetLen()) );
610 // #i16195# Literate copy from TextArray action, the
611 // semantics for the ImplLayout call are copied from the
612 // OutDev::DrawStretchText() code. Unfortunately, also in
613 // this case, public outdev methods such as GetTextWidth()
614 // don't provide enough info.
615 if( !aString
.isEmpty() )
617 // #105987# ImplLayout takes everything in logical coordinates
618 SalLayout
* pSalLayout
= rOut
.ImplLayout( rTextAct
.GetText(), rTextAct
.GetIndex(),
619 rTextAct
.GetLen(), rTextAct
.GetPoint(),
620 rTextAct
.GetWidth() );
623 tools::Rectangle
aBoundRect( const_cast<OutputDevice
&>(rOut
).ImplGetTextBoundRect( *pSalLayout
) );
624 aActionBounds
= rOut
.PixelToLogic( aBoundRect
);
625 pSalLayout
->Release();
631 case MetaActionType::TEXTLINE
:
632 OSL_FAIL("MetaActionType::TEXTLINE not supported");
639 if( !aActionBounds
.IsEmpty() )
641 // fdo#40421 limit current action's output to clipped area
642 if( rOut
.IsClipRegion() )
643 return rOut
.LogicToPixel(
644 rOut
.GetClipRegion().GetBoundRect().Intersection( aActionBounds
) );
646 return rOut
.LogicToPixel( aActionBounds
);
649 return tools::Rectangle();
652 } // end anon namespace
654 bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile
& rInMtf
, GDIMetaFile
& rOutMtf
,
655 long nMaxBmpDPIX
, long nMaxBmpDPIY
,
656 bool bReduceTransparency
, bool bTransparencyAutoMode
,
657 bool bDownsampleBitmaps
,
658 const Color
& rBackground
661 MetaAction
* pCurrAct
;
662 bool bTransparent( false );
666 if( ! bReduceTransparency
|| bTransparencyAutoMode
)
668 // watch for transparent drawing actions
669 for( pCurrAct
= const_cast<GDIMetaFile
&>(rInMtf
).FirstAction();
670 pCurrAct
&& !bTransparent
;
671 pCurrAct
= const_cast<GDIMetaFile
&>(rInMtf
).NextAction() )
673 // #i10613# determine if the action is transparency capable
675 // #107169# Also examine metafiles with masked bitmaps in
676 // detail. Further down, this is optimized in such a way
677 // that there's no unnecessary painting of masked bitmaps
678 // (which are _always_ subdivided into rectangular regions
679 // of uniform opacity): if a masked bitmap is printed over
680 // empty background, we convert to a plain bitmap with
682 if( IsTransparentAction( *pCurrAct
) )
689 // #i10613# Determine set of connected components containing transparent objects. These are
690 // then processed as bitmaps, the original actions are removed from the metafile.
693 // nothing transparent -> just copy
699 // This works as follows: we want a number of distinct sets of
700 // connected components, where each set contains metafile
701 // actions that are intersecting (note: there are possibly
702 // more actions contained as are directly intersecting,
703 // because we can only produce rectangular bitmaps later
704 // on. Thus, each set of connected components is the smallest
705 // enclosing, axis-aligned rectangle that completely bounds a
706 // number of intersecting metafile actions, plus any action
707 // that would otherwise be cut in two). Therefore, we
708 // iteratively add metafile actions from the original metafile
709 // to this connected components list (aCCList), by checking
710 // each element's bounding box against intersection with the
711 // metaaction at hand.
712 // All those intersecting elements are removed from aCCList
713 // and collected in a temporary list (aCCMergeList). After all
714 // elements have been checked, the aCCMergeList elements are
715 // merged with the metaaction at hand into one resulting
716 // connected component, with one big bounding box, and
717 // inserted into aCCList again.
718 // The time complexity of this algorithm is O(n^3), where n is
719 // the number of metafile actions, and it finds all distinct
720 // regions of rectangle-bounded connected components. This
721 // algorithm was designed by AF.
723 // STAGE 1: Detect background
725 // Receives uniform background content, and is _not_ merged
726 // nor checked for intersection against other aCCList elements
727 ConnectedComponents aBackgroundComponent
;
729 // create an OutputDevice to record mapmode changes and the like
730 ScopedVclPtrInstance
< VirtualDevice
> aMapModeVDev
;
731 aMapModeVDev
->mnDPIX
= mnDPIX
;
732 aMapModeVDev
->mnDPIY
= mnDPIY
;
733 aMapModeVDev
->EnableOutput(false);
735 int nLastBgAction
, nActionNum
;
737 // weed out page-filling background objects (if they are
738 // uniformly coloured). Keeping them outside the other
739 // connected components often prevents whole-page bitmap
741 bool bStillBackground
=true; // true until first non-bg action
742 nActionNum
=0; nLastBgAction
=-1;
743 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction();
744 if( rBackground
!= Color( COL_TRANSPARENT
) )
746 aBackgroundComponent
.aBgColor
= rBackground
;
747 if( meOutDevType
== OUTDEV_PRINTER
)
749 Printer
* pThis
= dynamic_cast<Printer
*>(this);
750 Point aPageOffset
= pThis
->GetPageOffsetPixel();
751 aPageOffset
= Point( 0, 0 ) - aPageOffset
;
752 Size aSize
= pThis
->GetPaperSizePixel();
753 aBackgroundComponent
.aBounds
= tools::Rectangle( aPageOffset
, aSize
);
756 aBackgroundComponent
.aBounds
= tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
758 while( pCurrAct
&& bStillBackground
)
760 switch( pCurrAct
->GetType() )
762 case MetaActionType::RECT
:
765 aBackgroundComponent
.aBounds
,
766 aBackgroundComponent
.aBgColor
,
767 static_cast<const MetaRectAction
*>(pCurrAct
)->GetRect(),
768 *aMapModeVDev
.get()) )
769 bStillBackground
=false; // incomplete occlusion of background
771 nLastBgAction
=nActionNum
; // this _is_ background
774 case MetaActionType::POLYGON
:
776 const tools::Polygon
aPoly(
777 static_cast<const MetaPolygonAction
*>(pCurrAct
)->GetPolygon());
778 if( !basegfx::tools::isRectangle(
779 aPoly
.getB2DPolygon()) ||
781 aBackgroundComponent
.aBounds
,
782 aBackgroundComponent
.aBgColor
,
783 aPoly
.GetBoundRect(),
784 *aMapModeVDev
.get()) )
785 bStillBackground
=false; // incomplete occlusion of background
787 nLastBgAction
=nActionNum
; // this _is_ background
790 case MetaActionType::POLYPOLYGON
:
792 const tools::PolyPolygon
aPoly(
793 static_cast<const MetaPolyPolygonAction
*>(pCurrAct
)->GetPolyPolygon());
794 if( aPoly
.Count() != 1 ||
795 !basegfx::tools::isRectangle(
796 aPoly
[0].getB2DPolygon()) ||
798 aBackgroundComponent
.aBounds
,
799 aBackgroundComponent
.aBgColor
,
800 aPoly
.GetBoundRect(),
801 *aMapModeVDev
.get()) )
802 bStillBackground
=false; // incomplete occlusion of background
804 nLastBgAction
=nActionNum
; // this _is_ background
807 case MetaActionType::WALLPAPER
:
810 aBackgroundComponent
.aBounds
,
811 aBackgroundComponent
.aBgColor
,
812 static_cast<const MetaWallpaperAction
*>(pCurrAct
)->GetRect(),
813 *aMapModeVDev
.get()) )
814 bStillBackground
=false; // incomplete occlusion of background
816 nLastBgAction
=nActionNum
; // this _is_ background
821 if( ImplIsNotTransparent( *pCurrAct
,
822 *aMapModeVDev
.get() ) )
823 bStillBackground
=false; // non-transparent action, possibly
826 // extend current bounds (next uniform action
827 // needs to fully cover this area)
828 aBackgroundComponent
.aBounds
.Union(
829 ImplCalcActionBounds(*pCurrAct
, *aMapModeVDev
.get()) );
834 // execute action to get correct MapModes etc.
835 pCurrAct
->Execute( aMapModeVDev
.get() );
837 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction();
841 // clean up aMapModeVDev
842 sal_uInt32 nCount
= aMapModeVDev
->GetGCStackDepth();
846 ConnectedComponentsList aCCList
; // list containing distinct sets of connected components as elements.
848 // fast-forward until one after the last background action
849 // (need to reconstruct map mode vdev state)
851 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction();
852 while( pCurrAct
&& nActionNum
<=nLastBgAction
)
854 // up to and including last ink-generating background
855 // action go to background component
856 aBackgroundComponent
.aComponentList
.push_back(
858 pCurrAct
, nActionNum
) );
860 // execute action to get correct MapModes etc.
861 pCurrAct
->Execute( aMapModeVDev
.get() );
862 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction();
866 // STAGE 2: Generate connected components list
868 // iterate over all actions (start where background action
872 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
874 // execute action to get correct MapModes etc.
875 pCurrAct
->Execute( aMapModeVDev
.get() );
877 // cache bounds of current action
878 const tools::Rectangle
aBBCurrAct( ImplCalcActionBounds(*pCurrAct
, *aMapModeVDev
.get()) );
880 // accumulate collected bounds here, initialize with current action
881 tools::Rectangle
aTotalBounds( aBBCurrAct
); // thus,
882 // aTotalComponents.aBounds
886 // non-output-generating
888 bool bTreatSpecial( false );
889 ConnectedComponents aTotalComponents
;
891 // STAGE 2.1: Search for intersecting cc entries
893 // if aBBCurrAct is empty, it will intersect with no
894 // aCCList member. Thus, we can save the check.
895 // Furthermore, this ensures that non-output-generating
896 // actions get their own aCCList entry, which is necessary
897 // when copying them to the output metafile (see stage 4
900 // #107169# Wholly transparent objects need
901 // not be considered for connected components,
902 // too. Just put each of them into a separate
904 aTotalComponents
.bIsFullyTransparent
= !ImplIsNotTransparent(*pCurrAct
, *aMapModeVDev
.get());
906 if( !aBBCurrAct
.IsEmpty() &&
907 !aTotalComponents
.bIsFullyTransparent
)
909 if( !aBackgroundComponent
.aComponentList
.empty() &&
910 !aBackgroundComponent
.aBounds
.IsInside(aTotalBounds
) )
912 // it seems the background is not large enough. to
913 // be on the safe side, combine with this component.
914 aTotalBounds
.Union( aBackgroundComponent
.aBounds
);
916 // extract all aCurr actions to aTotalComponents
917 aTotalComponents
.aComponentList
.splice( aTotalComponents
.aComponentList
.end(),
918 aBackgroundComponent
.aComponentList
);
920 if( aBackgroundComponent
.bIsSpecial
)
921 bTreatSpecial
= true;
924 ConnectedComponentsList::iterator aCurrCC
;
925 const ConnectedComponentsList::iterator
aLastCC( aCCList
.end() );
926 bool bSomeComponentsChanged
;
928 // now, this is unfortunate: since changing anyone of
929 // the aCCList elements (e.g. by merging or addition
930 // of an action) might generate new intersection with
931 // other aCCList elements, have to repeat the whole
932 // element scanning, until nothing changes anymore.
933 // Thus, this loop here makes us O(n^3) in the worst
937 // only loop here if 'intersects' branch below was hit
938 bSomeComponentsChanged
= false;
940 // iterate over all current members of aCCList
941 for( aCurrCC
=aCCList
.begin(); aCurrCC
!= aLastCC
; )
943 // first check if current element's bounds are
944 // empty. This ensures that empty actions are not
945 // merged into one component, as a matter of fact,
946 // they have no position.
948 // #107169# Wholly transparent objects need
949 // not be considered for connected components,
950 // too. Just put each of them into a separate
952 if( !aCurrCC
->aBounds
.IsEmpty() &&
953 !aCurrCC
->bIsFullyTransparent
&&
954 aCurrCC
->aBounds
.IsOver( aTotalBounds
) )
956 // union the intersecting aCCList element into aTotalComponents
958 // calc union bounding box
959 aTotalBounds
.Union( aCurrCC
->aBounds
);
961 // extract all aCurr actions to aTotalComponents
962 aTotalComponents
.aComponentList
.splice( aTotalComponents
.aComponentList
.end(),
963 aCurrCC
->aComponentList
);
965 if( aCurrCC
->bIsSpecial
)
966 bTreatSpecial
= true;
968 // remove and delete aCurrCC element from list (we've now merged its content)
969 aCurrCC
= aCCList
.erase( aCurrCC
);
971 // at least one component changed, need to rescan everything
972 bSomeComponentsChanged
= true;
980 while( bSomeComponentsChanged
);
983 // STAGE 2.2: Determine special state for cc element
985 // now test whether the whole connected component must be
986 // treated specially (i.e. rendered as a bitmap): if the
987 // added action is the very first action, or all actions
988 // before it are completely transparent, the connected
989 // component need not be treated specially, not even if
990 // the added action contains transparency. This is because
991 // painting of transparent objects on _white background_
992 // works without alpha compositing (you just calculate the
993 // color). Note that for the test "all objects before me
994 // are transparent" no sorting is necessary, since the
995 // added metaaction pCurrAct is always in the order the
996 // metafile is painted. Generally, the order of the
997 // metaactions in the ConnectedComponents are not
998 // guaranteed to be the same as in the metafile.
1001 // prev component(s) special -> this one, too
1002 aTotalComponents
.bIsSpecial
= true;
1004 else if( !IsTransparentAction( *pCurrAct
) )
1006 // added action and none of prev components special ->
1007 // this one normal, too
1008 aTotalComponents
.bIsSpecial
= false;
1012 // added action is special and none of prev components
1013 // special -> do the detailed tests
1015 // can the action handle transparency correctly
1016 // (i.e. when painted on white background, does the
1017 // action still look correct)?
1018 if( !DoesActionHandleTransparency( *pCurrAct
) )
1020 // no, action cannot handle its transparency on
1021 // a printer device, render to bitmap
1022 aTotalComponents
.bIsSpecial
= true;
1026 // yes, action can handle its transparency, so
1027 // check whether we're on white background
1028 if( aTotalComponents
.aComponentList
.empty() )
1030 // nothing between pCurrAct and page
1031 // background -> don't be special
1032 aTotalComponents
.bIsSpecial
= false;
1036 // #107169# Fixes above now ensure that _no_
1037 // object in the list is fully transparent. Thus,
1038 // if the component list is not empty above, we
1039 // must assume that we have to treat this
1040 // component special.
1042 // there are non-transparent objects between
1043 // pCurrAct and the empty sheet of paper -> be
1045 aTotalComponents
.bIsSpecial
= true;
1050 // STAGE 2.3: Add newly generated CC list element
1052 // set new bounds and add action to list
1053 aTotalComponents
.aBounds
= aTotalBounds
;
1054 aTotalComponents
.aComponentList
.push_back(
1056 pCurrAct
, nActionNum
) );
1058 // add aTotalComponents as a new entry to aCCList
1059 aCCList
.push_back( aTotalComponents
);
1061 SAL_WARN_IF( aTotalComponents
.aComponentList
.empty(), "vcl",
1062 "Printer::GetPreparedMetaFile empty component" );
1063 SAL_WARN_IF( aTotalComponents
.aBounds
.IsEmpty() && (aTotalComponents
.aComponentList
.size() != 1), "vcl",
1064 "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
1065 SAL_WARN_IF( aTotalComponents
.bIsFullyTransparent
&& (aTotalComponents
.aComponentList
.size() != 1), "vcl",
1066 "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
1069 // well now, we've got the list of disjunct connected
1070 // components. Now we've got to create a map, which contains
1071 // the corresponding aCCList element for every
1072 // metaaction. Later on, we always process the complete
1073 // metafile for each bitmap to be generated, but switch on
1074 // output only for actions contained in the then current
1075 // aCCList element. This ensures correct mapmode and attribute
1076 // settings for all cases.
1078 // maps mtf actions to CC list entries
1079 ::std::vector
< const ConnectedComponents
* > aCCList_MemberMap( rInMtf
.GetActionSize() );
1081 // iterate over all aCCList members and their contained metaactions
1082 ConnectedComponentsList::iterator
aCurr( aCCList
.begin() );
1083 const ConnectedComponentsList::iterator
aLast( aCCList
.end() );
1084 for( ; aCurr
!= aLast
; ++aCurr
)
1086 ComponentList::iterator
aCurrentAction( aCurr
->aComponentList
.begin() );
1087 const ComponentList::iterator
aLastAction( aCurr
->aComponentList
.end() );
1088 for( ; aCurrentAction
!= aLastAction
; ++aCurrentAction
)
1090 // set pointer to aCCList element for corresponding index
1091 aCCList_MemberMap
[ aCurrentAction
->second
] = &(*aCurr
);
1095 // STAGE 3.1: Output background mtf actions (if there are any)
1097 ComponentList::iterator
aCurrAct( aBackgroundComponent
.aComponentList
.begin() );
1098 const ComponentList::iterator
aLastAct( aBackgroundComponent
.aComponentList
.end() );
1099 for( ; aCurrAct
!= aLastAct
; ++aCurrAct
)
1101 // simply add this action (above, we inserted the actions
1102 // starting at index 0 up to and including nLastBgAction)
1103 rOutMtf
.AddAction( ( aCurrAct
->first
->Duplicate(), aCurrAct
->first
) );
1106 // STAGE 3.2: Generate banded bitmaps for special regions
1109 Size
aTmpSize( GetOutputSizePixel() );
1112 aTmpSize
= mpPDFWriter
->getCurPageSize();
1113 aTmpSize
= LogicToPixel( aTmpSize
, MapMode( MapUnit::MapPoint
) );
1115 // also add error code to PDFWriter
1116 mpPDFWriter
->insertError( vcl::PDFWriter::Warning_Transparency_Converted
);
1118 else if( meOutDevType
== OUTDEV_PRINTER
)
1120 Printer
* pThis
= dynamic_cast<Printer
*>(this);
1121 aPageOffset
= pThis
->GetPageOffsetPixel();
1122 aPageOffset
= Point( 0, 0 ) - aPageOffset
;
1123 aTmpSize
= pThis
->GetPaperSizePixel();
1125 const tools::Rectangle
aOutputRect( aPageOffset
, aTmpSize
);
1126 bool bTiling
= dynamic_cast<Printer
*>(this) != nullptr;
1128 // iterate over all aCCList members and generate bitmaps for the special ones
1129 for( aCurr
= aCCList
.begin(); aCurr
!= aLast
; ++aCurr
)
1131 if( aCurr
->bIsSpecial
)
1133 tools::Rectangle
aBoundRect( aCurr
->aBounds
);
1134 aBoundRect
.Intersection( aOutputRect
);
1136 const double fBmpArea( (double) aBoundRect
.GetWidth() * aBoundRect
.GetHeight() );
1137 const double fOutArea( (double) aOutputRect
.GetWidth() * aOutputRect
.GetHeight() );
1139 // check if output doesn't exceed given size
1140 if( bReduceTransparency
&& bTransparencyAutoMode
&& ( fBmpArea
> ( 0.25 * fOutArea
) ) )
1142 // output normally. Therefore, we simply clear the
1143 // special attribute, as everything non-special is
1144 // copied to rOutMtf further below.
1145 aCurr
->bIsSpecial
= false;
1149 // create new bitmap action first
1150 if( aBoundRect
.GetWidth() && aBoundRect
.GetHeight() )
1152 Point
aDstPtPix( aBoundRect
.TopLeft() );
1155 ScopedVclPtrInstance
<VirtualDevice
> aMapVDev
; // here, we record only mapmode information
1156 aMapVDev
->EnableOutput(false);
1158 ScopedVclPtrInstance
<VirtualDevice
> aPaintVDev
; // into this one, we render.
1159 aPaintVDev
->SetBackground( aBackgroundComponent
.aBgColor
);
1161 rOutMtf
.AddAction( new MetaPushAction( PushFlags::MAPMODE
) );
1162 rOutMtf
.AddAction( new MetaMapModeAction() );
1164 aPaintVDev
->SetDrawMode( GetDrawMode() );
1166 while( aDstPtPix
.Y() <= aBoundRect
.Bottom() )
1168 aDstPtPix
.X() = aBoundRect
.Left();
1169 aDstSzPix
= bTiling
? Size( MAX_TILE_WIDTH
, MAX_TILE_HEIGHT
) : aBoundRect
.GetSize();
1171 if( ( aDstPtPix
.Y() + aDstSzPix
.Height() - 1 ) > aBoundRect
.Bottom() )
1172 aDstSzPix
.Height() = aBoundRect
.Bottom() - aDstPtPix
.Y() + 1;
1174 while( aDstPtPix
.X() <= aBoundRect
.Right() )
1176 if( ( aDstPtPix
.X() + aDstSzPix
.Width() - 1 ) > aBoundRect
.Right() )
1177 aDstSzPix
.Width() = aBoundRect
.Right() - aDstPtPix
.X() + 1;
1179 if( !tools::Rectangle( aDstPtPix
, aDstSzPix
).Intersection( aBoundRect
).IsEmpty() &&
1180 aPaintVDev
->SetOutputSizePixel( aDstSzPix
) )
1185 aMapVDev
->mnDPIX
= aPaintVDev
->mnDPIX
= mnDPIX
;
1186 aMapVDev
->mnDPIY
= aPaintVDev
->mnDPIY
= mnDPIY
;
1188 aPaintVDev
->EnableOutput(false);
1190 // iterate over all actions
1191 for( pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction(), nActionNum
=0;
1193 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
1195 // enable output only for
1196 // actions that are members of
1197 // the current aCCList element
1199 if( aCCList_MemberMap
[nActionNum
] == &(*aCurr
) )
1200 aPaintVDev
->EnableOutput();
1202 // but process every action
1203 const MetaActionType
nType( pCurrAct
->GetType() );
1205 if( MetaActionType::MAPMODE
== nType
)
1207 pCurrAct
->Execute( aMapVDev
.get() );
1209 MapMode
aMtfMap( aMapVDev
->GetMapMode() );
1210 const Point
aNewOrg( aMapVDev
->PixelToLogic( aDstPtPix
) );
1212 aMtfMap
.SetOrigin( Point( -aNewOrg
.X(), -aNewOrg
.Y() ) );
1213 aPaintVDev
->SetMapMode( aMtfMap
);
1215 else if( ( MetaActionType::PUSH
== nType
) || ( MetaActionType::POP
) == nType
)
1217 pCurrAct
->Execute( aMapVDev
.get() );
1218 pCurrAct
->Execute( aPaintVDev
.get() );
1220 else if( MetaActionType::GRADIENT
== nType
)
1222 MetaGradientAction
* pGradientAction
= static_cast<MetaGradientAction
*>(pCurrAct
);
1223 Printer
* pPrinter
= dynamic_cast< Printer
* >(this);
1225 pPrinter
->DrawGradientEx( aPaintVDev
.get(), pGradientAction
->GetRect(), pGradientAction
->GetGradient() );
1227 DrawGradient( pGradientAction
->GetRect(), pGradientAction
->GetGradient() );
1231 pCurrAct
->Execute( aPaintVDev
.get() );
1234 if( !( nActionNum
% 8 ) )
1235 Application::Reschedule();
1238 const bool bOldMap
= mbMap
;
1239 mbMap
= aPaintVDev
->mbMap
= false;
1241 Bitmap
aBandBmp( aPaintVDev
->GetBitmap( Point(), aDstSzPix
) );
1243 // scale down bitmap, if requested
1244 if( bDownsampleBitmaps
)
1246 aBandBmp
= GetDownsampledBitmap( aDstSzPix
,
1247 Point(), aBandBmp
.GetSizePixel(),
1248 aBandBmp
, nMaxBmpDPIX
, nMaxBmpDPIY
);
1251 rOutMtf
.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
1252 rOutMtf
.AddAction( new MetaBmpScaleAction( aDstPtPix
, aDstSzPix
, aBandBmp
) );
1253 rOutMtf
.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
1255 aPaintVDev
->mbMap
= true;
1261 // overlapping bands to avoid missing lines (e.g. PostScript)
1262 aDstPtPix
.X() += aDstSzPix
.Width();
1265 // overlapping bands to avoid missing lines (e.g. PostScript)
1266 aDstPtPix
.Y() += aDstSzPix
.Height();
1269 rOutMtf
.AddAction( new MetaPopAction() );
1275 // clean up aMapModeVDev
1276 nCount
= aMapModeVDev
->GetGCStackDepth();
1278 aMapModeVDev
->Pop();
1280 // STAGE 4: Copy actions to output metafile
1282 // iterate over all actions and duplicate the ones not in a
1283 // special aCCList member into rOutMtf
1284 for( pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).FirstAction(), nActionNum
=0;
1286 pCurrAct
=const_cast<GDIMetaFile
&>(rInMtf
).NextAction(), ++nActionNum
)
1288 const ConnectedComponents
* pCurrAssociatedComponent
= aCCList_MemberMap
[nActionNum
];
1290 // NOTE: This relies on the fact that map-mode or draw
1291 // mode changing actions are solitary aCCList elements and
1292 // have empty bounding boxes, see comment on stage 2.1
1294 if( pCurrAssociatedComponent
&&
1295 (pCurrAssociatedComponent
->aBounds
.IsEmpty() ||
1296 !pCurrAssociatedComponent
->bIsSpecial
) )
1298 // #107169# Treat transparent bitmaps special, if they
1299 // are the first (or sole) action in their bounds
1300 // list. Note that we previously ensured that no
1301 // fully-transparent objects are before us here.
1302 if( DoesActionHandleTransparency( *pCurrAct
) &&
1303 pCurrAssociatedComponent
->aComponentList
.begin()->first
== pCurrAct
)
1305 // convert actions, where masked-out parts are of
1306 // given background color
1307 ImplConvertTransparentAction(rOutMtf
,
1309 *aMapModeVDev
.get(),
1310 aBackgroundComponent
.aBgColor
);
1314 // simply add this action
1315 rOutMtf
.AddAction( ( pCurrAct
->Duplicate(), pCurrAct
) );
1318 pCurrAct
->Execute(aMapModeVDev
.get());
1322 rOutMtf
.SetPrefMapMode( rInMtf
.GetPrefMapMode() );
1323 rOutMtf
.SetPrefSize( rInMtf
.GetPrefSize() );
1325 #if OSL_DEBUG_LEVEL > 1
1326 // iterate over all aCCList members and generate rectangles for the bounding boxes
1327 rOutMtf
.AddAction( new MetaFillColorAction( COL_WHITE
, false ) );
1328 for( aCurr
= aCCList
.begin(); aCurr
!= aLast
; ++aCurr
)
1330 if( aCurr
->bIsSpecial
)
1331 rOutMtf
.AddAction( new MetaLineColorAction( COL_RED
, true) );
1333 rOutMtf
.AddAction( new MetaLineColorAction( COL_BLUE
, true) );
1335 rOutMtf
.AddAction( new MetaRectAction( aMapModeVDev
->PixelToLogic( aCurr
->aBounds
) ) );
1339 return bTransparent
;
1342 void Printer::DrawGradientEx( OutputDevice
* pOut
, const tools::Rectangle
& rRect
, const Gradient
& rGradient
)
1344 const PrinterOptions
& rPrinterOptions
= GetPrinterOptions();
1346 if( rPrinterOptions
.IsReduceGradients() )
1348 if( PrinterGradientMode::Stripes
== rPrinterOptions
.GetReducedGradientMode() )
1350 if( !rGradient
.GetSteps() || ( rGradient
.GetSteps() > rPrinterOptions
.GetReducedGradientStepCount() ) )
1352 Gradient
aNewGradient( rGradient
);
1354 aNewGradient
.SetSteps( rPrinterOptions
.GetReducedGradientStepCount() );
1355 pOut
->DrawGradient( rRect
, aNewGradient
);
1358 pOut
->DrawGradient( rRect
, rGradient
);
1362 const Color
& rStartColor
= rGradient
.GetStartColor();
1363 const Color
& rEndColor
= rGradient
.GetEndColor();
1364 const long nR
= ( ( (long) rStartColor
.GetRed() * rGradient
.GetStartIntensity() ) / 100 +
1365 ( (long) rEndColor
.GetRed() * rGradient
.GetEndIntensity() ) / 100 ) >> 1;
1366 const long nG
= ( ( (long) rStartColor
.GetGreen() * rGradient
.GetStartIntensity() ) / 100 +
1367 ( (long) rEndColor
.GetGreen() * rGradient
.GetEndIntensity() ) / 100 ) >> 1;
1368 const long nB
= ( ( (long) rStartColor
.GetBlue() * rGradient
.GetStartIntensity() ) / 100 +
1369 ( (long) rEndColor
.GetBlue() * rGradient
.GetEndIntensity() ) / 100 ) >> 1;
1370 const Color
aColor( (sal_uInt8
) nR
, (sal_uInt8
) nG
, (sal_uInt8
) nB
);
1372 pOut
->Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
1373 pOut
->SetLineColor( aColor
);
1374 pOut
->SetFillColor( aColor
);
1375 pOut
->DrawRect( rRect
);
1380 pOut
->DrawGradient( rRect
, rGradient
);
1383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */