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