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 <vcl/bmpacc.hxx>
31 : : #include <tools/poly.hxx>
32 : : #include <vcl/outdev.hxx>
33 : : #include <vcl/window.hxx>
34 : : #include <vcl/gdimtf.hxx>
35 : : #include <vcl/metaact.hxx>
36 : : #include <vcl/metric.hxx>
37 : : #include <vcl/animate.hxx>
38 : : #include <vcl/alpha.hxx>
39 : : #include <vcl/virdev.hxx>
40 : : #include "grfcache.hxx"
41 : : #include <svtools/grfmgr.hxx>
42 : :
43 : : // -----------
44 : : // - defines -
45 : : // -----------
46 : :
47 : : #define WATERMARK_LUM_OFFSET 50
48 : : #define WATERMARK_CON_OFFSET -70
49 : :
50 : : // ------------------
51 : : // - GraphicManager -
52 : : // ------------------
53 : :
54 : 138 : GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) :
55 [ + - ][ + - ]: 138 : mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) )
56 : : {
57 : 138 : }
58 : :
59 : 51 : GraphicManager::~GraphicManager()
60 : : {
61 [ - + ]: 51 : for( size_t i = 0, n = maObjList.size(); i < n; ++i )
62 [ # # ][ # # ]: 0 : maObjList[ i ]->GraphicManagerDestroyed();
63 : :
64 [ + - ][ + - ]: 51 : delete mpCache;
65 : 51 : }
66 : :
67 : 0 : void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
68 : : {
69 : 0 : mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
70 : 0 : }
71 : :
72 : 0 : void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
73 : : {
74 : 0 : mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
75 : 0 : }
76 : :
77 : 138 : void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds )
78 : : {
79 : 138 : mpCache->SetCacheTimeout( nTimeoutSeconds );
80 : 138 : }
81 : :
82 : 48 : void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
83 : : {
84 : : // !!!
85 : 48 : }
86 : :
87 : 30 : sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
88 : : const Size& rSz, const GraphicObject& rObj,
89 : : const GraphicAttr& rAttr ) const
90 : : {
91 : 30 : return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
92 : : }
93 : :
94 : 17560 : sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
95 : : GraphicObject& rObj, const GraphicAttr& rAttr,
96 : : const sal_uLong nFlags, sal_Bool& rCached )
97 : : {
98 : 17560 : Point aPt( rPt );
99 : 17560 : Size aSz( rSz );
100 : 17560 : sal_Bool bRet = sal_False;
101 : :
102 : 17560 : rCached = sal_False;
103 : :
104 [ - + ][ # # ]: 17560 : if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
[ + - ]
105 : : {
106 : : // create output and fill cache
107 : :
108 [ + - ][ + - ]: 35145 : if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
[ + - ][ + - ]
[ + - + +
+ - ][ + + ]
109 : 17560 : ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
110 : : ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
111 : 17560 : !( nFlags & GRFMGR_DRAW_CACHED ) ||
112 : 17585 : ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
113 : : {
114 : : // simple output of transformed graphic
115 [ + - ]: 25 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
116 : :
117 [ + - ][ + - ]: 25 : if( aGraphic.IsSupportedGraphic() )
118 : : {
119 : 25 : const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
120 : :
121 [ - + ]: 25 : if( nRot10 )
122 : : {
123 [ # # ][ # # ]: 0 : Polygon aPoly( Rectangle( aPt, aSz ) );
124 : :
125 [ # # ]: 0 : aPoly.Rotate( aPt, nRot10 );
126 [ # # ]: 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
127 : 0 : aPt = aRotBoundRect.TopLeft();
128 [ # # ][ # # ]: 0 : aSz = aRotBoundRect.GetSize();
129 : : }
130 : :
131 [ + - ]: 25 : aGraphic.Draw( pOut, aPt, aSz );
132 : : }
133 : :
134 [ + - ]: 25 : bRet = sal_True;
135 : : }
136 : :
137 [ + + ]: 17560 : if( !bRet )
138 : : {
139 : : // cached/direct drawing
140 [ + - ][ + + ]: 17535 : if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
141 [ + - ]: 17534 : bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
142 : : else
143 : 1 : bRet = rCached = sal_True;
144 : : }
145 : : }
146 : :
147 : 17560 : return bRet;
148 : : }
149 : :
150 : 34781 : void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
151 : : const rtl::OString* pID, const GraphicObject* pCopyObj )
152 : : {
153 [ + - ]: 34781 : maObjList.push_back( (GraphicObject*)&rObj );
154 : 34781 : mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
155 : 34781 : }
156 : :
157 : 34530 : void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
158 : : {
159 : 34530 : mpCache->ReleaseGraphicObject( rObj );
160 [ + - ][ + - ]: 232820 : for( GraphicObjectList_impl::iterator it = maObjList.begin(); it != maObjList.end(); ++it )
[ + - ]
161 : : {
162 [ + - ][ + + ]: 232820 : if ( *it == &rObj ) {
163 [ + - ]: 34530 : maObjList.erase( it );
164 : 34530 : break;
165 : : }
166 : : }
167 : 34530 : }
168 : :
169 : 27 : void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
170 : : {
171 : 27 : mpCache->GraphicObjectWasSwappedOut( rObj );
172 : 27 : }
173 : :
174 : 5521 : rtl::OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
175 : : {
176 : 5521 : return mpCache->GetUniqueID( rObj );
177 : : }
178 : :
179 : 8 : sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
180 : : {
181 : 8 : return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
182 : : }
183 : :
184 : 6 : void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
185 : : {
186 : 6 : mpCache->GraphicObjectWasSwappedIn( rObj );
187 : 6 : }
188 : :
189 : 17534 : sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
190 : : const Size& rSz, GraphicObject& rObj,
191 : : const GraphicAttr& rAttr,
192 : : const sal_uLong nFlags, sal_Bool& rCached )
193 : : {
194 : 17534 : const Graphic& rGraphic = rObj.GetGraphic();
195 : 17534 : sal_Bool bRet = sal_False;
196 : :
197 [ + - ][ + - ]: 17534 : if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
[ + - ]
198 : : {
199 [ + - ]: 17534 : if( GRAPHIC_BITMAP == rGraphic.GetType() )
200 : : {
201 [ + - ]: 17534 : const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
202 : :
203 : : // #i46805# No point in caching a bitmap that is rendered
204 : : // via RectFill on the OutDev
205 [ + - ][ + - ]: 35068 : if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
[ + - ]
206 [ + - ]: 17534 : mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
207 : : {
208 [ + - ]: 17534 : BitmapEx aDstBmpEx;
209 : :
210 [ + - ][ + - ]: 17534 : if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
211 : : {
212 [ + - ]: 17534 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
213 : 17534 : bRet = sal_True;
214 [ + - ]: 17534 : }
215 : : }
216 : :
217 [ - + ]: 17534 : if( !bRet )
218 [ # # ][ + - ]: 17534 : bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
219 : : }
220 : : else
221 : : {
222 : 0 : const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
223 : :
224 [ # # ]: 0 : if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
225 : : {
226 [ # # ]: 0 : GDIMetaFile aDstMtf;
227 [ # # ]: 0 : BitmapEx aContainedBmpEx;
228 : :
229 [ # # ][ # # ]: 0 : if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
230 : : {
231 [ # # ]: 0 : if( !!aContainedBmpEx )
232 : : {
233 : : // Use bitmap output method, if metafile basically contains only a single
234 : : // bitmap (allows caching the resulting pixmap).
235 [ # # ]: 0 : BitmapEx aDstBmpEx;
236 : :
237 [ # # ][ # # ]: 0 : if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
238 : : {
239 [ # # ]: 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
240 : 0 : bRet = sal_True;
241 [ # # ]: 0 : }
242 : : }
243 : : else
244 : : {
245 [ # # ]: 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
246 : 0 : bRet = sal_True;
247 : : }
248 [ # # ][ # # ]: 0 : }
249 : : }
250 : :
251 [ # # ]: 0 : if( !bRet )
252 : : {
253 [ # # ]: 0 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
254 : :
255 [ # # ][ # # ]: 0 : if( aGraphic.IsSupportedGraphic() )
256 : : {
257 [ # # ]: 0 : aGraphic.Draw( pOut, rPt, rSz );
258 : 0 : bRet = sal_True;
259 [ # # ]: 0 : }
260 : : }
261 : : }
262 : : }
263 : :
264 : 17534 : return bRet;
265 : : }
266 : :
267 : 17534 : sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
268 : : const Point& rPoint, const Size& rSize,
269 : : const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes,
270 : : const sal_uLong nFlags, BitmapEx* pResultBitmapEx )
271 : : {
272 : 17534 : bool bRet = false;
273 : :
274 [ + - ]: 17534 : Point aUnrotatedPointInPixels( pOutputDevice->LogicToPixel( rPoint ) );
275 [ + - ]: 17534 : Size aUnrotatedSizeInPixels( pOutputDevice->LogicToPixel( rSize ) );
276 : :
277 [ + - ][ - + ]: 17534 : if( aUnrotatedSizeInPixels.Width() <= 0 || aUnrotatedSizeInPixels.Height() <= 0)
[ - + ]
278 : 0 : return false;
279 : :
280 : 17534 : Point aOutPointInPixels;
281 : 17534 : Size aOutSizeInPixels;
282 [ + - ]: 17534 : BitmapEx aBitmapEx( rBitmapEx );
283 : 17534 : int nRotation = rAttributes.GetRotation() % 3600;
284 : :
285 [ - + ]: 17534 : if( nRotation != 0 )
286 : : {
287 [ # # ][ # # ]: 0 : Polygon aPoly( Rectangle( rPoint, rSize ) );
288 [ # # ]: 0 : aPoly.Rotate( rPoint, nRotation );
289 [ # # ]: 0 : const Rectangle aRotationBoundRect( aPoly.GetBoundRect() );
290 [ # # ]: 0 : aOutPointInPixels = pOutputDevice->LogicToPixel( aRotationBoundRect.TopLeft() );
291 [ # # ][ # # ]: 0 : aOutSizeInPixels = pOutputDevice->LogicToPixel( aRotationBoundRect.GetSize() );
[ # # ]
292 : : }
293 : : else
294 : : {
295 : 17534 : aOutPointInPixels = aUnrotatedPointInPixels;
296 : 17534 : aOutSizeInPixels = aUnrotatedSizeInPixels;
297 : : }
298 : :
299 : 17534 : Point aOutPoint;
300 : 17534 : Size aOutSize;
301 : :
302 : 17534 : const Size& rBitmapSizePixels = rBitmapEx.GetSizePixel();
303 [ + - ]: 17534 : Rectangle aCropRectangle(0, 0, 0, 0);
304 : :
305 : 17534 : bool isHorizontalMirrored = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
306 : 17534 : bool isVerticalMirrored = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
307 : :
308 : : // calculate output sizes
309 : : if( true || !pResultBitmapEx )
310 : : {
311 [ + - ]: 17534 : Rectangle aBitmapRectangle( aOutPointInPixels, aOutSizeInPixels );
312 [ + - ]: 17534 : Rectangle aOutRect( Point(), pOutputDevice->GetOutputSizePixel() );
313 : :
314 [ - + ]: 17534 : if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW )
315 : : {
316 [ # # ]: 0 : const Region aPaintRegion( ( (Window*) pOutputDevice )->GetPaintRegion() );
317 : :
318 [ # # ][ # # ]: 0 : if( !aPaintRegion.IsNull() )
319 [ # # ][ # # ]: 0 : aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRegion.GetBoundRect() ) );
[ # # ][ # # ]
320 : : }
321 [ + - ]: 17534 : aOutRect.Intersection( aBitmapRectangle );
322 : :
323 [ + - ][ + + ]: 17534 : if( !aOutRect.IsEmpty() )
324 : : {
325 [ + - ]: 16562 : aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() );
326 [ + - ][ + - ]: 16562 : aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
327 : :
328 : : aCropRectangle = Rectangle(
329 : 16562 : aOutRect.Left() - aBitmapRectangle.Left(),
330 : 16562 : aOutRect.Top() - aBitmapRectangle.Top(),
331 : 16562 : aOutRect.Right() - aBitmapRectangle.Left(),
332 [ + - ]: 33124 : aOutRect.Bottom() - aBitmapRectangle.Top() );
333 : : }
334 : : }
335 : : else
336 : : {
337 : : aOutPoint = pOutputDevice->PixelToLogic( aOutPointInPixels );
338 : : aOutSize = pOutputDevice->PixelToLogic( aOutSizeInPixels );
339 : :
340 : : aCropRectangle = Rectangle(
341 : : 0, 0,
342 : : aOutSizeInPixels.Width() - 1,
343 : : aOutSizeInPixels.Height() - 1 );
344 : : }
345 : :
346 : :
347 [ + - ][ - + ]: 17534 : if( aCropRectangle.GetWidth() <= 0 && aCropRectangle.GetHeight() <= 0 )
[ # # ][ # # ]
[ - + ]
348 : 0 : return false;
349 : :
350 : : // do transformation
351 [ + - ][ + - ]: 35068 : if( !isHorizontalMirrored &&
[ + - + + ]
[ + + ]
352 : 17534 : !isVerticalMirrored &&
353 : : !nRotation &&
354 : 17534 : aOutSizeInPixels == rBitmapSizePixels)
355 : : {
356 : : // simple copy thorugh
357 [ + - ]: 4327 : aOutPoint = pOutputDevice->PixelToLogic( aOutPointInPixels );
358 [ + - ]: 4327 : aOutSize = pOutputDevice->PixelToLogic( aOutSizeInPixels );
359 : 4327 : bRet = true;
360 : : }
361 : : else
362 : : {
363 : : // mirror the image - this should not impact the picture dimenstions
364 [ + - ][ - + ]: 13207 : if( isHorizontalMirrored || isVerticalMirrored )
365 [ # # ]: 0 : bRet = aBitmapEx.Mirror( rAttributes.GetMirrorFlags() );
366 : :
367 : : // prepare rotation if needed
368 [ - + ]: 13207 : if (nRotation != 0)
369 : : {
370 [ # # ][ # # ]: 0 : Polygon aPoly( Rectangle( Point(), aUnrotatedSizeInPixels) );
371 [ # # ]: 0 : aPoly.Rotate( Point(), nRotation );
372 [ # # ]: 0 : Rectangle aNewBound( aPoly.GetBoundRect() );
373 : :
374 : : aCropRectangle = Rectangle (
375 : 0 : aCropRectangle.Left() + aNewBound.Left(),
376 : 0 : aCropRectangle.Top() + aNewBound.Top(),
377 : 0 : aCropRectangle.Right() + aNewBound.Left(),
378 [ # # ][ # # ]: 0 : aCropRectangle.Bottom() + aNewBound.Top() );
379 : : }
380 : :
381 : : // calculate scaling factors
382 : 13207 : double fScaleX = aUnrotatedSizeInPixels.Width() / (double) rBitmapSizePixels.Width();
383 : 13207 : double fScaleY = aUnrotatedSizeInPixels.Height() / (double) rBitmapSizePixels.Height();
384 : :
385 [ + - ]: 13207 : if( nFlags & GRFMGR_DRAW_SMOOTHSCALE )
386 : : {
387 [ + - ]: 13207 : bRet = aBitmapEx.ScaleCropRotate( fScaleX, fScaleY, aCropRectangle, nRotation, COL_TRANSPARENT );
388 : : }
389 : : else
390 : : {
391 : : aCropRectangle = Rectangle (
392 : 0 : aCropRectangle.Left() / fScaleX,
393 : 0 : aCropRectangle.Top() / fScaleY,
394 : 0 : aCropRectangle.Right() / fScaleX,
395 [ # # ]: 0 : aCropRectangle.Bottom() / fScaleY );
396 : :
397 [ # # ]: 0 : bRet = aBitmapEx.Crop( aCropRectangle );
398 [ # # ]: 0 : if ( bRet )
399 [ # # ]: 13207 : bRet = aBitmapEx.Scale( fScaleX, fScaleY );
400 : : }
401 : : }
402 : :
403 [ + - ]: 17534 : if( bRet )
404 : : {
405 : : // attribute adjustment if neccessary
406 [ + - + - : 52602 : if( rAttributes.IsSpecialDrawMode()
- + ][ - + ]
407 : 17534 : || rAttributes.IsAdjusted()
408 : 17534 : || rAttributes.IsTransparent() )
409 : : {
410 [ # # ]: 0 : ImplAdjust( aBitmapEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
411 : : }
412 : :
413 : : // OutDev adjustment if neccessary
414 [ + - ][ - + ]: 35068 : if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER
[ # # ][ - + ]
415 [ + - ]: 17534 : && pOutputDevice->GetBitCount() <= 8
416 [ # # ]: 0 : && aBitmapEx.GetBitCount() >= 8 )
417 : : {
418 [ # # ]: 0 : aBitmapEx.Dither( BMP_DITHER_MATRIX );
419 : : }
420 : : }
421 : :
422 : : // create output
423 [ + - ]: 17534 : if( bRet )
424 : : {
425 [ + - ]: 17534 : if( pResultBitmapEx )
426 : : {
427 [ + - ][ + - ]: 17534 : if( !rAttributes.IsTransparent() && !aBitmapEx.IsAlpha() )
[ + + ][ + + ]
428 [ + - ][ + - ]: 6 : aBitmapEx = BitmapEx( aBitmapEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aBitmapEx.GetMask() );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
429 : :
430 [ + - ]: 17534 : *pResultBitmapEx = aBitmapEx;
431 : : }
432 [ + - ]: 17534 : pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aBitmapEx);
433 : : }
434 : :
435 [ + - ]: 17534 : return bRet;
436 : : }
437 : :
438 : : // This function checks whether the bitmap is usable for skipping
439 : : // mtf rendering by using just this one bitmap (i.e. in case the metafile
440 : : // contains just this one pixmap that covers the entire metafile area).
441 : 0 : static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx,
442 : : Point rSrcPoint,
443 : : Size rSrcSize,
444 : : const Point& rDestPoint,
445 : : const Size& rDestSize,
446 : : const Size& rRefSize,
447 : : bool& o_rbNonBitmapActionEncountered )
448 : : {
449 : : // NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too.
450 : 0 : BitmapEx aBmpEx;
451 [ # # ]: 0 : if( rSrcSize == Size())
452 : 0 : rSrcSize = rBmpEx.GetSizePixel();
453 : :
454 [ # # ]: 0 : if( rDestPoint != Point( 0, 0 ))
455 : : { // The pixmap in the metafile has an offset (and so would not cover)
456 : : // the entire result -> fall back to mtf rendering.
457 : 0 : o_rbNonBitmapActionEncountered = true;
458 : 0 : return aBmpEx;
459 : : }
460 [ # # ]: 0 : if( rDestSize != rRefSize )
461 : : { // The pixmap is not fullscale (does not cover the entire metafile area).
462 : : // HACK: The code here should refuse to use the bitmap directly
463 : : // and fall back to mtf rendering, but there seem to be metafiles
464 : : // that do not specify exactly their area (the Windows API requires apps
465 : : // the specify it manually, the rectangle is specified as topleft/bottomright
466 : : // rather than topleft/size [which may be confusing], and the docs
467 : : // on the exact meaning are somewhat confusing as well), so if it turns
468 : : // out this metafile really contains just one bitmap and no other painting,
469 : : // and if the sizes almost match, just use the pixmap (which will be scaled
470 : : // to fit exactly the requested size, so there should not be any actual problem
471 : : // caused by this small difference). This will allow caching of the resulting
472 : : // (scaled) pixmap, which can make a noticeable performance difference.
473 [ # # ][ # # : 0 : if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
# # # # ]
[ # # ]
474 : 0 : && abs( rDestSize.Width() - rRefSize.Width()) < 5
475 : 0 : && abs( rDestSize.Height() - rRefSize.Height()) < 5 )
476 : : ; // ok, assume it's close enough
477 : : else
478 : : { // fall back to mtf rendering
479 : 0 : o_rbNonBitmapActionEncountered = true;
480 : 0 : return aBmpEx;
481 : : }
482 : : }
483 : :
484 [ # # ]: 0 : aBmpEx = rBmpEx;
485 : :
486 [ # # ]: 0 : if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
[ # # # # ]
[ # # ]
487 : 0 : rSrcSize != rBmpEx.GetSizePixel() )
488 : : {
489 : : // crop bitmap to given source rectangle (no
490 : : // need to copy and convert the whole bitmap)
491 : : const Rectangle aCropRect( rSrcPoint,
492 [ # # ]: 0 : rSrcSize );
493 [ # # ]: 0 : aBmpEx.Crop( aCropRect );
494 : : }
495 : :
496 : 0 : return aBmpEx;
497 : : }
498 : :
499 : 0 : sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut,
500 : : const Point& rPt, const Size& rSz,
501 : : const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
502 : : const sal_uLong /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
503 : : {
504 : 0 : const Size aNewSize( rMtf.GetPrefSize() );
505 : :
506 [ # # ]: 0 : rOutMtf = rMtf;
507 : :
508 : : // Count bitmap actions, and flag actions that paint, but
509 : : // are no bitmaps.
510 : 0 : sal_Int32 nNumBitmaps(0);
511 : 0 : bool bNonBitmapActionEncountered(false);
512 [ # # ][ # # ]: 0 : if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
[ # # ][ # # ]
[ # # ]
513 : : {
514 : 0 : const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
515 : 0 : const double fOutWH = (double) rSz.Width() / rSz.Height();
516 : :
517 : 0 : const double fScaleX = fOutWH / fGrfWH;
518 : 0 : const double fScaleY = 1.0;
519 : :
520 [ # # ]: 0 : const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
521 [ # # ]: 0 : const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
522 : :
523 : : // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap
524 : : // in grfcache.cxx too.
525 : :
526 : : // Determine whether the metafile basically displays
527 : : // a single bitmap (in which case that bitmap is simply used directly
528 : : // instead of playing the metafile). Note that
529 : : // the solution, as implemented here, is quite suboptimal (the
530 : : // cases where a mtf consisting basically of a single bitmap,
531 : : // that fail to pass the test below, are probably frequent). A
532 : : // better solution would involve FSAA, but that's currently
533 : : // expensive, and might trigger bugs on display drivers, if
534 : : // VDevs get bigger than the actual screen.
535 : : sal_uInt32 nCurPos;
536 : : MetaAction* pAct;
537 [ # # ][ # # ]: 0 : for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
[ # # ]
538 : : pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
539 : : {
540 : 0 : MetaAction* pModAct = NULL;
541 [ # # # # : 0 : switch( pAct->GetType() )
# # # # #
# ]
542 : : {
543 : : case META_FONT_ACTION:
544 : : {
545 : : // taking care of font width default if scaling metafile.
546 : 0 : MetaFontAction* pA = (MetaFontAction*)pAct;
547 [ # # ]: 0 : Font aFont( pA->GetFont() );
548 [ # # ][ # # ]: 0 : if ( !aFont.GetWidth() )
549 : : {
550 [ # # ]: 0 : FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
551 [ # # ][ # # ]: 0 : aFont.SetWidth( aFontMetric.GetWidth() );
552 [ # # ][ # # ]: 0 : pModAct = new MetaFontAction( aFont );
[ # # ]
553 [ # # ]: 0 : }
554 : : }
555 : : // FALLTHROUGH intended
556 : : case META_NULL_ACTION:
557 : : // FALLTHROUGH intended
558 : :
559 : : // OutDev state changes (which don't affect bitmap
560 : : // output)
561 : : case META_LINECOLOR_ACTION:
562 : : // FALLTHROUGH intended
563 : : case META_FILLCOLOR_ACTION:
564 : : // FALLTHROUGH intended
565 : : case META_TEXTCOLOR_ACTION:
566 : : // FALLTHROUGH intended
567 : : case META_TEXTFILLCOLOR_ACTION:
568 : : // FALLTHROUGH intended
569 : : case META_TEXTALIGN_ACTION:
570 : : // FALLTHROUGH intended
571 : : case META_TEXTLINECOLOR_ACTION:
572 : : // FALLTHROUGH intended
573 : : case META_TEXTLINE_ACTION:
574 : : // FALLTHROUGH intended
575 : : case META_PUSH_ACTION:
576 : : // FALLTHROUGH intended
577 : : case META_POP_ACTION:
578 : : // FALLTHROUGH intended
579 : : case META_LAYOUTMODE_ACTION:
580 : : // FALLTHROUGH intended
581 : : case META_TEXTLANGUAGE_ACTION:
582 : : // FALLTHROUGH intended
583 : : case META_COMMENT_ACTION:
584 : 0 : break;
585 : :
586 : : // bitmap output methods
587 : : case META_BMP_ACTION:
588 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
589 : : {
590 : 0 : MetaBmpAction* pAction = (MetaBmpAction*)pAct;
591 : :
592 : : rOutBmpEx = checkMetadataBitmap(
593 : 0 : BitmapEx( pAction->GetBitmap()),
594 : : Point(), Size(),
595 : 0 : pOut->LogicToPixel( pAction->GetPoint(),
596 : : rPrefMapMode ),
597 : 0 : pAction->GetBitmap().GetSizePixel(),
598 : : rSizePix,
599 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # ][ # # ]
[ # # ]
[ # # # # ]
600 : : }
601 : 0 : ++nNumBitmaps;
602 : 0 : break;
603 : :
604 : : case META_BMPSCALE_ACTION:
605 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
606 : : {
607 : 0 : MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
608 : :
609 : : rOutBmpEx = checkMetadataBitmap(
610 : 0 : BitmapEx( pAction->GetBitmap()),
611 : : Point(), Size(),
612 : 0 : pOut->LogicToPixel( pAction->GetPoint(),
613 : : rPrefMapMode ),
614 : 0 : pOut->LogicToPixel( pAction->GetSize(),
615 : : rPrefMapMode ),
616 : : rSizePix,
617 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # ][ # # ]
[ # # ]
[ # # # # ]
618 : : }
619 : 0 : ++nNumBitmaps;
620 : 0 : break;
621 : :
622 : : case META_BMPSCALEPART_ACTION:
623 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
624 : : {
625 : 0 : MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
626 : :
627 : : rOutBmpEx = checkMetadataBitmap(
628 : 0 : BitmapEx( pAction->GetBitmap() ),
629 : 0 : pAction->GetSrcPoint(),
630 : 0 : pAction->GetSrcSize(),
631 : 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
632 : : rPrefMapMode ),
633 : 0 : pOut->LogicToPixel( pAction->GetDestSize(),
634 : : rPrefMapMode ),
635 : : rSizePix,
636 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # ][ # # ]
[ # # # #
# # ]
637 : : }
638 : 0 : ++nNumBitmaps;
639 : 0 : break;
640 : :
641 : : case META_BMPEX_ACTION:
642 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
643 : : {
644 : 0 : MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
645 : :
646 : : rOutBmpEx = checkMetadataBitmap(
647 : 0 : pAction->GetBitmapEx(),
648 : : Point(), Size(),
649 : 0 : pOut->LogicToPixel( pAction->GetPoint(),
650 : : rPrefMapMode ),
651 : 0 : pAction->GetBitmapEx().GetSizePixel(),
652 : : rSizePix,
653 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # ][ # # ]
654 : : }
655 : 0 : ++nNumBitmaps;
656 : 0 : break;
657 : :
658 : : case META_BMPEXSCALE_ACTION:
659 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
660 : : {
661 : 0 : MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
662 : :
663 : : rOutBmpEx = checkMetadataBitmap(
664 : 0 : pAction->GetBitmapEx(),
665 : : Point(), Size(),
666 : 0 : pOut->LogicToPixel( pAction->GetPoint(),
667 : : rPrefMapMode ),
668 : 0 : pOut->LogicToPixel( pAction->GetSize(),
669 : : rPrefMapMode ),
670 : : rSizePix,
671 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # ]
[ # # # # ]
672 : : }
673 : 0 : ++nNumBitmaps;
674 : 0 : break;
675 : :
676 : : case META_BMPEXSCALEPART_ACTION:
677 [ # # ][ # # ]: 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
678 : : {
679 : 0 : MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
680 : :
681 : 0 : rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(),
682 : 0 : pAction->GetSrcPoint(),
683 : 0 : pAction->GetSrcSize(),
684 : 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
685 : : rPrefMapMode ),
686 : 0 : pOut->LogicToPixel( pAction->GetDestSize(),
687 : : rPrefMapMode ),
688 : : rSizePix,
689 [ # # ][ # # ]: 0 : bNonBitmapActionEncountered );
[ # # # #
# # ]
690 : : }
691 : 0 : ++nNumBitmaps;
692 : 0 : break;
693 : :
694 : : // these actions actually output something (that's
695 : : // different from a bitmap)
696 : : case META_RASTEROP_ACTION:
697 [ # # ]: 0 : if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
698 : 0 : break;
699 : : // FALLTHROUGH intended
700 : : case META_PIXEL_ACTION:
701 : : // FALLTHROUGH intended
702 : : case META_POINT_ACTION:
703 : : // FALLTHROUGH intended
704 : : case META_LINE_ACTION:
705 : : // FALLTHROUGH intended
706 : : case META_RECT_ACTION:
707 : : // FALLTHROUGH intended
708 : : case META_ROUNDRECT_ACTION:
709 : : // FALLTHROUGH intended
710 : : case META_ELLIPSE_ACTION:
711 : : // FALLTHROUGH intended
712 : : case META_ARC_ACTION:
713 : : // FALLTHROUGH intended
714 : : case META_PIE_ACTION:
715 : : // FALLTHROUGH intended
716 : : case META_CHORD_ACTION:
717 : : // FALLTHROUGH intended
718 : : case META_POLYLINE_ACTION:
719 : : // FALLTHROUGH intended
720 : : case META_POLYGON_ACTION:
721 : : // FALLTHROUGH intended
722 : : case META_POLYPOLYGON_ACTION:
723 : : // FALLTHROUGH intended
724 : :
725 : : case META_TEXT_ACTION:
726 : : // FALLTHROUGH intended
727 : : case META_TEXTARRAY_ACTION:
728 : : // FALLTHROUGH intended
729 : : case META_STRETCHTEXT_ACTION:
730 : : // FALLTHROUGH intended
731 : : case META_TEXTRECT_ACTION:
732 : : // FALLTHROUGH intended
733 : :
734 : : case META_MASK_ACTION:
735 : : // FALLTHROUGH intended
736 : : case META_MASKSCALE_ACTION:
737 : : // FALLTHROUGH intended
738 : : case META_MASKSCALEPART_ACTION:
739 : : // FALLTHROUGH intended
740 : :
741 : : case META_GRADIENT_ACTION:
742 : : // FALLTHROUGH intended
743 : : case META_HATCH_ACTION:
744 : : // FALLTHROUGH intended
745 : : case META_WALLPAPER_ACTION:
746 : : // FALLTHROUGH intended
747 : :
748 : : case META_TRANSPARENT_ACTION:
749 : : // FALLTHROUGH intended
750 : : case META_EPS_ACTION:
751 : : // FALLTHROUGH intended
752 : : case META_FLOATTRANSPARENT_ACTION:
753 : : // FALLTHROUGH intended
754 : : case META_GRADIENTEX_ACTION:
755 : : // FALLTHROUGH intended
756 : : case META_RENDERGRAPHIC_ACTION:
757 : : // FALLTHROUGH intended
758 : :
759 : : // OutDev state changes that _do_ affect bitmap
760 : : // output
761 : : case META_CLIPREGION_ACTION:
762 : : // FALLTHROUGH intended
763 : : case META_ISECTRECTCLIPREGION_ACTION:
764 : : // FALLTHROUGH intended
765 : : case META_ISECTREGIONCLIPREGION_ACTION:
766 : : // FALLTHROUGH intended
767 : : case META_MOVECLIPREGION_ACTION:
768 : : // FALLTHROUGH intended
769 : :
770 : : case META_MAPMODE_ACTION:
771 : : // FALLTHROUGH intended
772 : : case META_REFPOINT_ACTION:
773 : : // FALLTHROUGH intended
774 : : default:
775 : 0 : bNonBitmapActionEncountered = true;
776 : 0 : break;
777 : : }
778 [ # # ]: 0 : if ( pModAct )
779 : : {
780 [ # # ]: 0 : rOutMtf.ReplaceAction( pModAct, nCurPos );
781 [ # # ]: 0 : pAct->Delete();
782 : : }
783 : : else
784 : : {
785 [ # # ]: 0 : if( pAct->GetRefCount() > 1 )
786 : : {
787 [ # # ][ # # ]: 0 : rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
788 [ # # ]: 0 : pAct->Delete();
789 : : }
790 : : else
791 : 0 : pModAct = pAct;
792 : : }
793 [ # # ]: 0 : pModAct->Scale( fScaleX, fScaleY );
794 : : }
795 : 0 : rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
796 [ # # ]: 0 : FRound( aNewSize.Height() * fScaleY ) ) );
797 : : }
798 : :
799 [ # # ][ # # ]: 0 : if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
800 : : {
801 [ # # ][ # # ]: 0 : if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
[ # # ][ # # ]
[ # # ][ # # ]
802 [ # # ]: 0 : ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
803 : :
804 [ # # ]: 0 : ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
805 [ # # ][ # # ]: 0 : rOutBmpEx = BitmapEx();
[ # # ]
806 : : }
807 : :
808 : 0 : return sal_True;
809 : : }
810 : :
811 : 0 : void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
812 : : {
813 : 0 : GraphicAttr aAttr( rAttr );
814 : :
815 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
[ # # ]
816 : : {
817 [ # # # # ]: 0 : switch( aAttr.GetDrawMode() )
818 : : {
819 : : case( GRAPHICDRAWMODE_MONO ):
820 [ # # ]: 0 : rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
821 : 0 : break;
822 : :
823 : : case( GRAPHICDRAWMODE_GREYS ):
824 [ # # ]: 0 : rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
825 : 0 : break;
826 : :
827 : : case( GRAPHICDRAWMODE_WATERMARK ):
828 : : {
829 : 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
830 : 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
831 : : }
832 : 0 : break;
833 : :
834 : : default:
835 : 0 : break;
836 : : }
837 : : }
838 : :
839 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
[ # # ]
840 : : {
841 : 0 : rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
842 : 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
843 [ # # ]: 0 : aAttr.GetGamma(), aAttr.IsInvert() );
844 : : }
845 : :
846 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
[ # # ]
847 : : {
848 [ # # ]: 0 : rBmpEx.Mirror( aAttr.GetMirrorFlags() );
849 : : }
850 : :
851 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
[ # # ]
852 : : {
853 [ # # ]: 0 : rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
854 : : }
855 : :
856 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
[ # # ]
857 : : {
858 [ # # ]: 0 : AlphaMask aAlpha;
859 : 0 : sal_uInt8 cTrans = aAttr.GetTransparency();
860 : :
861 [ # # ][ # # ]: 0 : if( !rBmpEx.IsTransparent() )
862 [ # # ][ # # ]: 0 : aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
[ # # ]
863 [ # # ][ # # ]: 0 : else if( !rBmpEx.IsAlpha() )
864 : : {
865 [ # # ][ # # ]: 0 : aAlpha = rBmpEx.GetMask();
[ # # ]
866 [ # # ]: 0 : aAlpha.Replace( 0, cTrans );
867 : : }
868 : : else
869 : : {
870 [ # # ][ # # ]: 0 : aAlpha = rBmpEx.GetAlpha();
[ # # ]
871 [ # # ]: 0 : BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
872 : :
873 [ # # ]: 0 : if( pA )
874 : : {
875 : 0 : sal_uLong nTrans = cTrans, nNewTrans;
876 : 0 : const long nWidth = pA->Width(), nHeight = pA->Height();
877 : :
878 [ # # ]: 0 : if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
879 : : {
880 [ # # ]: 0 : for( long nY = 0; nY < nHeight; nY++ )
881 : : {
882 : 0 : Scanline pAScan = pA->GetScanline( nY );
883 : :
884 [ # # ]: 0 : for( long nX = 0; nX < nWidth; nX++ )
885 : : {
886 : 0 : nNewTrans = nTrans + *pAScan;
887 [ # # ]: 0 : *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
888 : : }
889 : : }
890 : : }
891 : : else
892 : : {
893 : 0 : BitmapColor aAlphaValue( 0 );
894 : :
895 [ # # ]: 0 : for( long nY = 0; nY < nHeight; nY++ )
896 : : {
897 [ # # ]: 0 : for( long nX = 0; nX < nWidth; nX++ )
898 : : {
899 [ # # ]: 0 : nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
900 [ # # ]: 0 : aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
901 [ # # ]: 0 : pA->SetPixel( nY, nX, aAlphaValue );
902 : : }
903 : 0 : }
904 : : }
905 : :
906 [ # # ]: 0 : aAlpha.ReleaseAccess( pA );
907 : : }
908 : : }
909 : :
910 [ # # ][ # # ]: 0 : rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
[ # # ][ # # ]
[ # # ][ # # ]
911 [ # # ]: 0 : }
912 : 0 : }
913 : :
914 : 0 : void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
915 : : {
916 : 0 : GraphicAttr aAttr( rAttr );
917 : :
918 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
[ # # ]
919 : : {
920 [ # # # # ]: 0 : switch( aAttr.GetDrawMode() )
921 : : {
922 : : case( GRAPHICDRAWMODE_MONO ):
923 [ # # ]: 0 : rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
924 : 0 : break;
925 : :
926 : : case( GRAPHICDRAWMODE_GREYS ):
927 [ # # ]: 0 : rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
928 : 0 : break;
929 : :
930 : : case( GRAPHICDRAWMODE_WATERMARK ):
931 : : {
932 : 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
933 : 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
934 : : }
935 : 0 : break;
936 : :
937 : : default:
938 : 0 : break;
939 : : }
940 : : }
941 : :
942 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
[ # # ]
943 : : {
944 : 0 : rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
945 : 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
946 [ # # ]: 0 : aAttr.GetGamma(), aAttr.IsInvert() );
947 : : }
948 : :
949 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
[ # # ]
950 : : {
951 [ # # ]: 0 : rMtf.Mirror( aAttr.GetMirrorFlags() );
952 : : }
953 : :
954 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
[ # # ]
955 : : {
956 [ # # ]: 0 : rMtf.Rotate( aAttr.GetRotation() );
957 : : }
958 : :
959 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
960 : : {
961 : : OSL_FAIL( "Missing implementation: Mtf-Transparency" );
962 [ # # ]: 0 : }
963 : 0 : }
964 : :
965 : 0 : void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
966 : : {
967 : 0 : GraphicAttr aAttr( rAttr );
968 : :
969 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
[ # # ]
970 : : {
971 [ # # # # ]: 0 : switch( aAttr.GetDrawMode() )
972 : : {
973 : : case( GRAPHICDRAWMODE_MONO ):
974 [ # # ]: 0 : rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
975 : 0 : break;
976 : :
977 : : case( GRAPHICDRAWMODE_GREYS ):
978 [ # # ]: 0 : rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
979 : 0 : break;
980 : :
981 : : case( GRAPHICDRAWMODE_WATERMARK ):
982 : : {
983 : 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
984 : 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
985 : : }
986 : 0 : break;
987 : :
988 : : default:
989 : 0 : break;
990 : : }
991 : : }
992 : :
993 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
[ # # ]
994 : : {
995 : 0 : rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
996 : 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
997 [ # # ]: 0 : aAttr.GetGamma(), aAttr.IsInvert() );
998 : : }
999 : :
1000 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
[ # # ]
1001 : : {
1002 [ # # ]: 0 : rAnimation.Mirror( aAttr.GetMirrorFlags() );
1003 : : }
1004 : :
1005 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1006 : : {
1007 : : OSL_FAIL( "Missing implementation: Animation-Rotation" );
1008 : : }
1009 : :
1010 [ # # ][ # # ]: 0 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1011 : : {
1012 : : OSL_FAIL( "Missing implementation: Animation-Transparency" );
1013 [ # # ]: 0 : }
1014 : 0 : }
1015 : :
1016 : 0 : void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1017 : : const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1018 : : {
1019 : 0 : sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
1020 : 0 : Point aOutPt( rPt );
1021 : 0 : Size aOutSz( rSz );
1022 : :
1023 [ # # ]: 0 : if( nRot10 )
1024 : : {
1025 [ # # ][ # # ]: 0 : Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1026 : :
1027 [ # # ]: 0 : aPoly.Rotate( aOutPt, nRot10 );
1028 [ # # ]: 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1029 : 0 : aOutPt = aRotBoundRect.TopLeft();
1030 [ # # ][ # # ]: 0 : aOutSz = aRotBoundRect.GetSize();
1031 : : }
1032 : :
1033 [ # # ]: 0 : pOut->Push( PUSH_CLIPREGION );
1034 [ # # ][ # # ]: 0 : pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1035 : :
1036 [ # # ]: 0 : ( (GDIMetaFile&) rMtf ).WindStart();
1037 [ # # ]: 0 : ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1038 [ # # ]: 0 : ( (GDIMetaFile&) rMtf ).WindStart();
1039 : :
1040 [ # # ]: 0 : pOut->Pop();
1041 : 0 : }
1042 : :
1043 : : struct ImplTileInfo
1044 : : {
1045 : 0 : ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1046 : :
1047 : : Point aTileTopLeft; // top, left position of the rendered tile
1048 : : Point aNextTileTopLeft; // top, left position for next recursion
1049 : : // level's tile
1050 : : Size aTileSizePixel; // size of the generated tile (might
1051 : : // differ from
1052 : : // aNextTileTopLeft-aTileTopLeft, because
1053 : : // this is nExponent*prevTileSize. The
1054 : : // generated tile is always nExponent
1055 : : // times the previous tile, such that it
1056 : : // can be used in the next stage. The
1057 : : // required area coverage is often
1058 : : // less. The extraneous area covered is
1059 : : // later overwritten by the next stage)
1060 : : int nTilesEmptyX; // number of original tiles empty right of
1061 : : // this tile. This counts from
1062 : : // aNextTileTopLeft, i.e. the additional
1063 : : // area covered by aTileSizePixel is not
1064 : : // considered here. This is for
1065 : : // unification purposes, as the iterative
1066 : : // calculation of the next level's empty
1067 : : // tiles has to be based on this value.
1068 : : int nTilesEmptyY; // as above, for Y
1069 : : };
1070 : :
1071 : :
1072 : 0 : bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
1073 : : int nNumTilesX, int nNumTilesY,
1074 : : const Size& rTileSizePixel,
1075 : : const GraphicAttr* pAttr, sal_uLong nFlags )
1076 : : {
1077 [ # # ]: 0 : if( nExponent <= 1 )
1078 : 0 : return false;
1079 : :
1080 : : // determine MSB factor
1081 : 0 : int nMSBFactor( 1 );
1082 [ # # ][ # # ]: 0 : while( nNumTilesX / nMSBFactor != 0 ||
[ # # ]
1083 : : nNumTilesY / nMSBFactor != 0 )
1084 : : {
1085 : 0 : nMSBFactor *= nExponent;
1086 : : }
1087 : :
1088 : : // one less
1089 : 0 : nMSBFactor /= nExponent;
1090 : :
1091 : 0 : ImplTileInfo aTileInfo;
1092 : :
1093 : : // #105229# Switch off mapping (converting to logic and back to
1094 : : // pixel might cause roundoff errors)
1095 : 0 : sal_Bool bOldMap( rVDev.IsMapModeEnabled() );
1096 [ # # ]: 0 : rVDev.EnableMapMode( sal_False );
1097 : :
1098 : : bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
1099 [ # # ]: 0 : nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
1100 : :
1101 [ # # ]: 0 : rVDev.EnableMapMode( bOldMap );
1102 : :
1103 : 0 : return bRet;
1104 : : }
1105 : :
1106 : : // define for debug drawings
1107 : : //#define DBG_TEST
1108 : :
1109 : : // see header comment. this works similar to base conversion of a
1110 : : // number, i.e. if the exponent is 10, then the number for every tile
1111 : : // size is given by the decimal place of the corresponding decimal
1112 : : // representation.
1113 : 0 : bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
1114 : : int nNumOrigTilesX, int nNumOrigTilesY,
1115 : : int nRemainderTilesX, int nRemainderTilesY,
1116 : : const Size& rTileSizePixel, const GraphicAttr* pAttr,
1117 : : sal_uLong nFlags, ImplTileInfo& rTileInfo )
1118 : : {
1119 : : // gets loaded with our tile bitmap
1120 [ # # ]: 0 : GraphicObject aTmpGraphic;
1121 : :
1122 : : // stores a flag that renders the zero'th tile position
1123 : : // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1124 : : // recursion stack. All other position already have that tile
1125 : : // rendered, because the lower levels painted their generated tile
1126 : : // there.
1127 : 0 : bool bNoFirstTileDraw( false );
1128 : :
1129 : : // what's left when we're done with our tile size
1130 : 0 : const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
1131 : 0 : const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
1132 : :
1133 : : // gets filled out from the recursive call with info of what's
1134 : : // been generated
1135 : 0 : ImplTileInfo aTileInfo;
1136 : :
1137 : : // current output position while drawing
1138 : 0 : Point aCurrPos;
1139 : : int nX, nY;
1140 : :
1141 : : // check for recursion's end condition: LSB place reached?
1142 [ # # ]: 0 : if( nMSBFactor == 1 )
1143 : : {
1144 [ # # ]: 0 : aTmpGraphic = *this;
1145 : :
1146 : : // set initial tile size -> orig size
1147 : 0 : aTileInfo.aTileSizePixel = rTileSizePixel;
1148 : 0 : aTileInfo.nTilesEmptyX = nNumOrigTilesX;
1149 : 0 : aTileInfo.nTilesEmptyY = nNumOrigTilesY;
1150 : : }
1151 [ # # ][ # # ]: 0 : else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
1152 : : nNumOrigTilesX, nNumOrigTilesY,
1153 : : nNewRemainderX, nNewRemainderY,
1154 : 0 : rTileSizePixel, pAttr, nFlags, aTileInfo ) )
1155 : : {
1156 : : // extract generated tile -> see comment on the first loop below
1157 [ # # ][ # # ]: 0 : BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
[ # # ]
1158 : :
1159 [ # # ][ # # ]: 0 : aTmpGraphic = GraphicObject( aTileBitmap );
[ # # ][ # # ]
[ # # ]
1160 : :
1161 : : // fill stripes left over from upstream levels:
1162 : : //
1163 : : // x0000
1164 : : // 0
1165 : : // 0
1166 : : // 0
1167 : : // 0
1168 : : //
1169 : : // where x denotes the place filled by our recursive predecessors
1170 : :
1171 : : // check whether we have to fill stripes here. Although not
1172 : : // obvious, there is one case where we can skip this step: if
1173 : : // the previous recursion level (the one who filled our
1174 : : // aTileInfo) had zero area to fill, then there are no white
1175 : : // stripes left, naturally. This happens if the digit
1176 : : // associated to that level has a zero, and can be checked via
1177 : : // aTileTopLeft==aNextTileTopLeft.
1178 [ # # ]: 0 : if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
1179 : : {
1180 : : // now fill one row from aTileInfo.aNextTileTopLeft.X() all
1181 : : // the way to the right
1182 : 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1183 : 0 : aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
1184 [ # # ]: 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
1185 : : {
1186 [ # # ][ # # ]: 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1187 : 0 : return false;
1188 : :
1189 : 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1190 : : }
1191 : :
1192 : : #ifdef DBG_TEST
1193 : : // rVDev.SetFillColor( COL_WHITE );
1194 : : rVDev.SetFillColor();
1195 : : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1196 : : rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
1197 : : aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
1198 : : aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
1199 : : #endif
1200 : :
1201 : : // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
1202 : : // the way to the bottom
1203 : 0 : aCurrPos.X() = aTileInfo.aTileTopLeft.X();
1204 : 0 : aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
1205 [ # # ]: 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
1206 : : {
1207 [ # # ][ # # ]: 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1208 : 0 : return false;
1209 : :
1210 : 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1211 : : }
1212 : :
1213 : : #ifdef DBG_TEST
1214 : : rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
1215 : : aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
1216 : : aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
1217 : : #endif
1218 : : }
1219 : : else
1220 : : {
1221 : : // Thought that aTileInfo.aNextTileTopLeft tile has always
1222 : : // been drawn already, but that's wrong: typically,
1223 : : // _parts_ of that tile have been drawn, since the
1224 : : // previous level generated the tile there. But when
1225 : : // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
1226 : : // difference between these two values is missing in the
1227 : : // lower right corner of this first tile. So, can do that
1228 : : // only here.
1229 : 0 : bNoFirstTileDraw = true;
1230 [ # # ][ # # ]: 0 : }
1231 : : }
1232 : : else
1233 : : {
1234 : 0 : return false;
1235 : : }
1236 : :
1237 : : // calc number of original tiles in our drawing area without
1238 : : // remainder
1239 : 0 : nRemainderTilesX -= nNewRemainderX;
1240 : 0 : nRemainderTilesY -= nNewRemainderY;
1241 : :
1242 : : // fill tile info for calling method
1243 : 0 : rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
1244 : 0 : rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
1245 : 0 : rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
1246 : 0 : rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
1247 : 0 : rTileSizePixel.Height()*nMSBFactor*nExponent );
1248 : 0 : rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
1249 : 0 : rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
1250 : :
1251 : : // init output position
1252 : 0 : aCurrPos = aTileInfo.aNextTileTopLeft;
1253 : :
1254 : : // fill our drawing area. Fill possibly more, to create the next
1255 : : // bigger tile size -> see bitmap extraction above. This does no
1256 : : // harm, since everything right or below our actual area is
1257 : : // overdrawn by our caller. Just in case we're in the last level,
1258 : : // we don't draw beyond the right or bottom border.
1259 [ # # ][ # # ]: 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
[ # # ]
1260 : : {
1261 : 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1262 : :
1263 [ # # ][ # # ]: 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
[ # # ]
1264 : : {
1265 [ # # ]: 0 : if( bNoFirstTileDraw )
1266 : 0 : bNoFirstTileDraw = false; // don't draw first tile position
1267 [ # # ][ # # ]: 0 : else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1268 : 0 : return false;
1269 : :
1270 : 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1271 : : }
1272 : :
1273 : 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1274 : : }
1275 : :
1276 : : #ifdef DBG_TEST
1277 : : // rVDev.SetFillColor( COL_WHITE );
1278 : : rVDev.SetFillColor();
1279 : : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1280 : : rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
1281 : : (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
1282 : : (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
1283 : : (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
1284 : : #endif
1285 : :
1286 [ # # ]: 0 : return true;
1287 : : }
1288 : :
1289 : 0 : bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
1290 : : const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
1291 : : {
1292 : : // how many tiles to generate per recursion step
1293 : : enum{ SubdivisionExponent=2 };
1294 : :
1295 [ # # ]: 0 : const MapMode aOutMapMode( pOut->GetMapMode() );
1296 [ # # ]: 0 : const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
1297 : 0 : bool bRet( false );
1298 : :
1299 : : // #i42643# Casting to Int64, to avoid integer overflow for
1300 : : // huge-DPI output devices
1301 [ # # ][ # # ]: 0 : if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
[ # # # # ]
[ # # ]
1302 : 0 : static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
1303 : : static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
1304 : : {
1305 : : // First combine very small bitmaps into a larger tile
1306 : : // ===================================================
1307 : :
1308 [ # # ]: 0 : VirtualDevice aVDev;
1309 : 0 : const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
1310 : 0 : const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
1311 : :
1312 : 0 : aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
1313 [ # # ]: 0 : nNumTilesInCacheY*rSizePixel.Height() ) );
1314 [ # # ]: 0 : aVDev.SetMapMode( aMapMode );
1315 : :
1316 : : // draw bitmap content
1317 [ # # ][ # # ]: 0 : if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1318 : : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1319 : : {
1320 [ # # ][ # # ]: 0 : BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
[ # # ][ # # ]
1321 : :
1322 : : // draw alpha content, if any
1323 [ # # ]: 0 : if( IsTransparent() )
1324 : : {
1325 [ # # ]: 0 : GraphicObject aAlphaGraphic;
1326 : :
1327 [ # # ][ # # ]: 0 : if( GetGraphic().IsAlpha() )
[ # # ]
1328 [ # # ][ # # ]: 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1329 : : else
1330 [ # # ][ # # ]: 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1331 : :
1332 [ # # ][ # # ]: 0 : if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1333 : : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1334 : : {
1335 : : // Combine bitmap and alpha/mask
1336 [ # # ][ # # ]: 0 : if( GetGraphic().IsAlpha() )
[ # # ]
1337 : : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1338 [ # # ][ # # ]: 0 : AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1339 : : else
1340 : : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1341 [ # # ][ # # ]: 0 : aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1342 [ # # ]: 0 : }
1343 : : }
1344 : :
1345 : : // paint generated tile
1346 [ # # ][ # # ]: 0 : GraphicObject aTmpGraphic( aTileBitmap );
[ # # ]
1347 : : bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
1348 : 0 : aTileBitmap.GetSizePixel(),
1349 [ # # ][ # # ]: 0 : rOffset, pAttr, nFlags, nTileCacheSize1D );
[ # # ]
1350 [ # # ]: 0 : }
1351 : : }
1352 : : else
1353 : : {
1354 [ # # ]: 0 : const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
1355 [ # # ]: 0 : const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
1356 : :
1357 : : // number of invisible (because out-of-area) tiles
1358 : : int nInvisibleTilesX;
1359 : : int nInvisibleTilesY;
1360 : :
1361 : : // round towards -infty for negative offset
1362 [ # # ]: 0 : if( aOutOffset.Width() < 0 )
1363 : 0 : nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
1364 : : else
1365 : 0 : nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
1366 : :
1367 : : // round towards -infty for negative offset
1368 [ # # ]: 0 : if( aOutOffset.Height() < 0 )
1369 : 0 : nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
1370 : : else
1371 : 0 : nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
1372 : :
1373 : : // origin from where to 'virtually' start drawing in pixel
1374 : 0 : const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
1375 [ # # ]: 0 : rArea.Top() - rOffset.Height() ) ) );
1376 : : // position in pixel from where to really start output
1377 : 0 : const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
1378 : 0 : aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
1379 : :
1380 [ # # ]: 0 : pOut->Push( PUSH_CLIPREGION );
1381 [ # # ]: 0 : pOut->IntersectClipRegion( rArea );
1382 : :
1383 : : // Paint all tiles
1384 : : // ===============
1385 : :
1386 : : bRet = ImplDrawTiled( *pOut, aOutStart,
1387 [ # # ]: 0 : (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
1388 [ # # ]: 0 : (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
1389 [ # # ]: 0 : rSizePixel, pAttr, nFlags );
1390 : :
1391 [ # # ]: 0 : pOut->Pop();
1392 : : }
1393 : :
1394 [ # # ][ # # ]: 0 : return bRet;
1395 : : }
1396 : :
1397 : 0 : bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
1398 : : int nNumTilesX, int nNumTilesY,
1399 : : const Size& rTileSizePixel, const GraphicAttr* pAttr, sal_uLong nFlags )
1400 : : {
1401 : 0 : Point aCurrPos( rPosPixel );
1402 [ # # ]: 0 : Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
1403 : : int nX, nY;
1404 : :
1405 : : // #107607# Use logical coordinates for metafile playing, too
1406 [ # # ][ # # ]: 0 : bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
1407 : 0 : bool bRet = false;
1408 : :
1409 : : // #105229# Switch off mapping (converting to logic and back to
1410 : : // pixel might cause roundoff errors)
1411 : 0 : bool bOldMap( rOut.IsMapModeEnabled() );
1412 : :
1413 [ # # ]: 0 : if( bDrawInPixel )
1414 [ # # ]: 0 : rOut.EnableMapMode( sal_False );
1415 : :
1416 [ # # ]: 0 : for( nY=0; nY < nNumTilesY; ++nY )
1417 : : {
1418 : 0 : aCurrPos.X() = rPosPixel.X();
1419 : :
1420 [ # # ]: 0 : for( nX=0; nX < nNumTilesX; ++nX )
1421 : : {
1422 : : // #105229# work with pixel coordinates here, mapping is disabled!
1423 : : // #104004# don't disable mapping for metafile recordings
1424 : : // #108412# don't quit the loop if one draw fails
1425 : :
1426 : : // update return value. This method should return true, if
1427 : : // at least one of the looped Draws succeeded.
1428 : : bRet |= Draw( &rOut,
1429 : : bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
1430 : : bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
1431 [ # # ][ # # ]: 0 : pAttr, nFlags );
[ # # ][ # # ]
1432 : :
1433 : 0 : aCurrPos.X() += rTileSizePixel.Width();
1434 : : }
1435 : :
1436 : 0 : aCurrPos.Y() += rTileSizePixel.Height();
1437 : : }
1438 : :
1439 [ # # ]: 0 : if( bDrawInPixel )
1440 [ # # ]: 0 : rOut.EnableMapMode( bOldMap );
1441 : :
1442 : 0 : return bRet;
1443 : : }
1444 : :
1445 : 0 : void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
1446 : : const GraphicAttr& rAttr,
1447 : : const Size& rCropLeftTop,
1448 : : const Size& rCropRightBottom,
1449 : : const Rectangle& rCropRect,
1450 : : const Size& rDstSize,
1451 : : sal_Bool bEnlarge ) const
1452 : : {
1453 : : // #107947# Extracted from svdograf.cxx
1454 : :
1455 : : // #104115# Crop the bitmap
1456 [ # # ]: 0 : if( rAttr.IsCropped() )
1457 : : {
1458 [ # # ]: 0 : rBmpEx.Crop( rCropRect );
1459 : :
1460 : : // #104115# Negative crop sizes mean: enlarge bitmap and pad
1461 [ # # # # : 0 : if( bEnlarge && (
# # # # #
# ][ # # ]
1462 : 0 : rCropLeftTop.Width() < 0 ||
1463 : 0 : rCropLeftTop.Height() < 0 ||
1464 : 0 : rCropRightBottom.Width() < 0 ||
1465 : 0 : rCropRightBottom.Height() < 0 ) )
1466 : : {
1467 : 0 : Size aBmpSize( rBmpEx.GetSizePixel() );
1468 [ # # ]: 0 : sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
1469 [ # # ]: 0 : sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
1470 [ # # ]: 0 : sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
1471 [ # # ]: 0 : sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
1472 : :
1473 [ # # ]: 0 : BitmapEx aBmpEx2;
1474 : :
1475 [ # # ][ # # ]: 0 : if( rBmpEx.IsTransparent() )
1476 : : {
1477 [ # # ][ # # ]: 0 : if( rBmpEx.IsAlpha() )
1478 [ # # ][ # # ]: 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1479 : : else
1480 [ # # ][ # # ]: 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1481 : : }
1482 : : else
1483 : : {
1484 : : // #104115# Generate mask bitmap and init to zero
1485 [ # # ]: 0 : Bitmap aMask( aBmpSize, 1 );
1486 [ # # ]: 0 : aMask.Erase( Color(0,0,0) );
1487 : :
1488 : : // #104115# Always generate transparent bitmap, we need the border transparent
1489 [ # # ][ # # ]: 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
[ # # ][ # # ]
[ # # ]
1490 : :
1491 : : // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
1492 [ # # ][ # # ]: 0 : rBmpEx = aBmpEx2;
1493 : : }
1494 : :
1495 [ # # ]: 0 : aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
1496 [ # # ]: 0 : aBmpEx2.Erase( Color(0xFF,0,0,0) );
1497 [ # # ][ # # ]: 0 : aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
[ # # ]
1498 [ # # ][ # # ]: 0 : rBmpEx = aBmpEx2;
1499 : : }
1500 : : }
1501 : :
1502 : 0 : const Size aSizePixel( rBmpEx.GetSizePixel() );
1503 : :
1504 [ # # ][ # # ]: 0 : if( rAttr.GetRotation() != 0 && !IsAnimated() )
[ # # ]
1505 : : {
1506 [ # # ][ # # ]: 0 : if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
[ # # ][ # # ]
[ # # ]
1507 : : {
1508 : 0 : double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
1509 : 0 : double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
1510 : 0 : double fScaleX = 1.0, fScaleY = 1.0;
1511 : :
1512 : : // always choose scaling to shrink bitmap
1513 [ # # ]: 0 : if( fSrcWH < fDstWH )
1514 : 0 : fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
1515 : : else
1516 : 0 : fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
1517 : :
1518 [ # # ]: 0 : rBmpEx.Scale( fScaleX, fScaleY );
1519 : : }
1520 : : }
1521 : 0 : }
1522 : :
1523 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|