Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <vcl/bmpacc.hxx>
21 : #include <tools/poly.hxx>
22 : #include <vcl/outdev.hxx>
23 : #include <vcl/window.hxx>
24 : #include <vcl/gdimtf.hxx>
25 : #include <vcl/metaact.hxx>
26 : #include <vcl/metric.hxx>
27 : #include <vcl/animate.hxx>
28 : #include <vcl/alpha.hxx>
29 : #include <vcl/virdev.hxx>
30 : #include "grfcache.hxx"
31 : #include <svtools/grfmgr.hxx>
32 :
33 : // -----------
34 : // - defines -
35 : // -----------
36 :
37 : #define WATERMARK_LUM_OFFSET 50
38 : #define WATERMARK_CON_OFFSET -70
39 : #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
40 :
41 : // ------------------
42 : // - GraphicManager -
43 : // ------------------
44 :
45 18 : GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) :
46 18 : mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) )
47 : {
48 18 : }
49 :
50 4 : GraphicManager::~GraphicManager()
51 : {
52 2 : for( size_t i = 0, n = maObjList.size(); i < n; ++i )
53 0 : maObjList[ i ]->GraphicManagerDestroyed();
54 :
55 2 : delete mpCache;
56 2 : }
57 :
58 0 : void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
59 : {
60 0 : mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
61 0 : }
62 :
63 0 : void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
64 : {
65 0 : mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
66 0 : }
67 :
68 18 : void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds )
69 : {
70 18 : mpCache->SetCacheTimeout( nTimeoutSeconds );
71 18 : }
72 :
73 0 : void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
74 : {
75 : // !!!
76 0 : }
77 :
78 16 : sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
79 : const Size& rSz, const GraphicObject& rObj,
80 : const GraphicAttr& rAttr ) const
81 : {
82 16 : return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
83 : }
84 :
85 24 : sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
86 : GraphicObject& rObj, const GraphicAttr& rAttr,
87 : const sal_uLong nFlags, sal_Bool& rCached )
88 : {
89 24 : Point aPt( rPt );
90 24 : Size aSz( rSz );
91 24 : sal_Bool bRet = sal_False;
92 :
93 24 : rCached = sal_False;
94 :
95 24 : if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
96 : {
97 : // create output and fill cache
98 :
99 104 : if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
100 24 : ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
101 : ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
102 24 : !( nFlags & GRFMGR_DRAW_CACHED ) ||
103 32 : ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
104 : {
105 : // simple output of transformed graphic
106 8 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
107 :
108 8 : if( aGraphic.IsSupportedGraphic() )
109 : {
110 8 : const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
111 :
112 8 : if( nRot10 )
113 : {
114 0 : Polygon aPoly( Rectangle( aPt, aSz ) );
115 :
116 0 : aPoly.Rotate( aPt, nRot10 );
117 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
118 0 : aPt = aRotBoundRect.TopLeft();
119 0 : aSz = aRotBoundRect.GetSize();
120 : }
121 :
122 8 : aGraphic.Draw( pOut, aPt, aSz );
123 : }
124 :
125 8 : bRet = sal_True;
126 : }
127 :
128 24 : if( !bRet )
129 : {
130 : // cached/direct drawing
131 16 : if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
132 8 : bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
133 : else
134 8 : bRet = rCached = sal_True;
135 : }
136 : }
137 :
138 24 : return bRet;
139 : }
140 :
141 2019 : void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
142 : const rtl::OString* pID, const GraphicObject* pCopyObj )
143 : {
144 2019 : maObjList.push_back( (GraphicObject*)&rObj );
145 2019 : mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
146 2019 : }
147 :
148 1768 : void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
149 : {
150 1768 : mpCache->ReleaseGraphicObject( rObj );
151 33837 : for( GraphicObjectList_impl::iterator it = maObjList.begin(); it != maObjList.end(); ++it )
152 : {
153 33837 : if ( *it == &rObj ) {
154 1768 : maObjList.erase( it );
155 1768 : break;
156 : }
157 : }
158 1768 : }
159 :
160 13 : void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
161 : {
162 13 : mpCache->GraphicObjectWasSwappedOut( rObj );
163 13 : }
164 :
165 132 : rtl::OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
166 : {
167 132 : return mpCache->GetUniqueID( rObj );
168 : }
169 :
170 0 : sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
171 : {
172 0 : return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
173 : }
174 :
175 0 : void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
176 : {
177 0 : mpCache->GraphicObjectWasSwappedIn( rObj );
178 0 : }
179 :
180 8 : sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
181 : const Size& rSz, GraphicObject& rObj,
182 : const GraphicAttr& rAttr,
183 : const sal_uLong nFlags, sal_Bool& rCached )
184 : {
185 8 : const Graphic& rGraphic = rObj.GetGraphic();
186 8 : sal_Bool bRet = sal_False;
187 :
188 8 : if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
189 : {
190 8 : if( GRAPHIC_BITMAP == rGraphic.GetType() )
191 : {
192 7 : const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
193 :
194 : // #i46805# No point in caching a bitmap that is rendered
195 : // via RectFill on the OutDev
196 14 : if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
197 7 : mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
198 : {
199 7 : BitmapEx aDstBmpEx;
200 :
201 7 : if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
202 : {
203 7 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
204 7 : bRet = sal_True;
205 7 : }
206 : }
207 :
208 7 : if( !bRet )
209 0 : bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
210 : }
211 : else
212 : {
213 1 : const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
214 :
215 1 : if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
216 : {
217 1 : GDIMetaFile aDstMtf;
218 1 : BitmapEx aContainedBmpEx;
219 :
220 1 : if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
221 : {
222 1 : if( !!aContainedBmpEx )
223 : {
224 : // Use bitmap output method, if metafile basically contains only a single
225 : // bitmap (allows caching the resulting pixmap).
226 0 : BitmapEx aDstBmpEx;
227 :
228 0 : if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
229 : {
230 0 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
231 0 : bRet = sal_True;
232 0 : }
233 : }
234 : else
235 : {
236 1 : rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
237 1 : bRet = sal_True;
238 : }
239 1 : }
240 : }
241 :
242 1 : if( !bRet )
243 : {
244 0 : const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
245 :
246 0 : if( aGraphic.IsSupportedGraphic() )
247 : {
248 0 : aGraphic.Draw( pOut, rPt, rSz );
249 0 : bRet = sal_True;
250 0 : }
251 : }
252 : }
253 : }
254 :
255 8 : return bRet;
256 : }
257 :
258 4 : sal_Bool ImplCreateRotatedScaled( const BitmapEx& rBmpEx, const GraphicAttr& rAttributes,
259 : sal_uInt16 nRot10, const Size& rUnrotatedSzPix,
260 : long nStartX, long nEndX, long nStartY, long nEndY,
261 : BitmapEx& rOutBmpEx )
262 : {
263 4 : const long aUnrotatedWidth = rUnrotatedSzPix.Width();
264 4 : const long aUnrotatedHeight = rUnrotatedSzPix.Height();
265 4 : const long aBitmapWidth = rBmpEx.GetSizePixel().Width();
266 4 : const long aBitmapHeight = rBmpEx.GetSizePixel().Height();
267 :
268 : long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nTmp;
269 : double fTmp;
270 :
271 4 : bool bHMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
272 4 : bool bVMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
273 :
274 4 : long* pMapIX = new long[ aUnrotatedWidth ];
275 4 : long* pMapFX = new long[ aUnrotatedWidth ];
276 4 : long* pMapIY = new long[ aUnrotatedHeight ];
277 4 : long* pMapFY = new long[ aUnrotatedHeight ];
278 :
279 4 : const double fScaleX = ( aUnrotatedWidth - 1 ) / (double) ( aBitmapWidth - 1 );
280 4 : const double fScaleY = ( aUnrotatedHeight - 1 ) / (double) ( aBitmapHeight - 1 );
281 :
282 4 : const double fRevScaleX = 1.0 / fScaleX;
283 4 : const double fRevScaleY = 1.0 / fScaleY;
284 :
285 : int x,y;
286 :
287 : // create horizontal mapping table
288 878 : for( x = 0, nTmpX = aBitmapWidth - 1L, nTmp = aBitmapWidth - 2L; x < aUnrotatedWidth; x++ )
289 : {
290 874 : fTmp = x * fRevScaleX;
291 :
292 874 : if( bHMirr )
293 0 : fTmp = nTmpX - fTmp;
294 :
295 874 : pMapIX[ x ] = MinMax( fTmp, 0, nTmp );
296 874 : pMapFX[ x ] = (long) ( ( fTmp - pMapIX[ x ] ) * 1048576.0 );
297 : }
298 :
299 : // create vertical mapping table
300 230 : for( y = 0, nTmpY = aBitmapHeight - 1L, nTmp = aBitmapHeight - 2L; y < aUnrotatedHeight; y++ )
301 : {
302 226 : fTmp = y * fRevScaleY;
303 :
304 226 : if( bVMirr )
305 0 : fTmp = nTmpY - fTmp;
306 :
307 226 : pMapIY[ y ] = MinMax( fTmp, 0, nTmp );
308 226 : pMapFY[ y ] = (long) ( ( fTmp - pMapIY[ y ] ) * 1048576.0 );
309 : }
310 :
311 :
312 4 : Bitmap aBmp( rBmpEx.GetBitmap() );
313 4 : Bitmap aOutBmp;
314 4 : BitmapReadAccess* pReadAccess = aBmp.AcquireReadAccess();
315 : BitmapWriteAccess* pWriteAccess;
316 :
317 4 : const double fCosAngle = cos( nRot10 * F_PI1800 );
318 4 : const double fSinAngle = sin( nRot10 * F_PI1800 );
319 4 : const long aTargetWidth = nEndX - nStartX + 1L;
320 4 : const long aTargetHeight = nEndY - nStartY + 1L;
321 4 : long* pCosX = new long[ aTargetWidth ];
322 4 : long* pSinX = new long[ aTargetWidth ];
323 4 : long* pCosY = new long[ aTargetHeight ];
324 4 : long* pSinY = new long[ aTargetHeight ];
325 : long nUnRotX, nUnRotY, nSinY, nCosY;
326 : sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
327 4 : bool bRet = false;
328 :
329 4 : Polygon aPoly( Rectangle( Point(), rUnrotatedSzPix ) );
330 4 : aPoly.Rotate( Point(), nRot10 );
331 4 : Rectangle aNewBound( aPoly.GetBoundRect() );
332 :
333 4 : bool scaleByAveraging = fScaleX < 0.6 || fScaleY < 0.6;
334 :
335 : // create horizontal mapping table
336 878 : for( x = 0, nTmpX = aNewBound.Left() + nStartX; x < aTargetWidth; x++ )
337 : {
338 874 : pCosX[ x ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
339 874 : pSinX[ x ] = FRound( fSinAngle * fTmp );
340 : }
341 :
342 : // create vertical mapping table
343 230 : for( y = 0, nTmpY = aNewBound.Top() + nStartY; y < aTargetHeight; y++ )
344 : {
345 226 : pCosY[ y ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
346 226 : pSinY[ y ] = FRound( fSinAngle * fTmp );
347 : }
348 :
349 4 : if( pReadAccess )
350 : {
351 4 : aOutBmp = Bitmap( Size( aTargetWidth, aTargetHeight ), 24 );
352 4 : pWriteAccess = aOutBmp.AcquireWriteAccess();
353 :
354 4 : if( pWriteAccess )
355 : {
356 4 : BitmapColor aColRes;
357 :
358 4 : if ( !scaleByAveraging )
359 : {
360 4 : if( pReadAccess->HasPalette() )
361 : {
362 131 : for( y = 0; y < aTargetHeight; y++ )
363 : {
364 129 : nSinY = pSinY[ y ];
365 129 : nCosY = pCosY[ y ];
366 :
367 68996 : for( x = 0; x < aTargetWidth; x++ )
368 : {
369 68867 : nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
370 68867 : nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
371 :
372 68867 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
373 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
374 : {
375 68867 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
376 68867 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
377 :
378 68867 : const BitmapColor& rCol0 = pReadAccess->GetPaletteColor( pReadAccess->GetPixel( nTmpY, nTmpX ) );
379 68867 : const BitmapColor& rCol1 = pReadAccess->GetPaletteColor( pReadAccess->GetPixel( nTmpY, ++nTmpX ) );
380 68867 : cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
381 68867 : cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
382 68867 : cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
383 :
384 68867 : const BitmapColor& rCol3 = pReadAccess->GetPaletteColor( pReadAccess->GetPixel( ++nTmpY, nTmpX ) );
385 68867 : const BitmapColor& rCol2 = pReadAccess->GetPaletteColor( pReadAccess->GetPixel( nTmpY, --nTmpX ) );
386 68867 : cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
387 68867 : cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
388 68867 : cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
389 :
390 68867 : aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
391 68867 : aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
392 68867 : aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
393 68867 : pWriteAccess->SetPixel( y, x, aColRes );
394 : }
395 : }
396 : }
397 : }
398 : else
399 : {
400 2 : BitmapColor aCol0, aCol1;
401 :
402 99 : for( y = 0; y < aTargetHeight; y++ )
403 : {
404 97 : nSinY = pSinY[ y ];
405 97 : nCosY = pCosY[ y ];
406 :
407 7561 : for( x = 0; x < aTargetWidth; x++ )
408 : {
409 7464 : nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
410 7464 : nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
411 :
412 7464 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
413 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
414 : {
415 7464 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
416 7464 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
417 :
418 7464 : aCol0 = pReadAccess->GetPixel( nTmpY, nTmpX );
419 7464 : aCol1 = pReadAccess->GetPixel( nTmpY, ++nTmpX );
420 7464 : cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
421 7464 : cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
422 7464 : cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
423 :
424 7464 : aCol1 = pReadAccess->GetPixel( ++nTmpY, nTmpX );
425 7464 : aCol0 = pReadAccess->GetPixel( nTmpY, --nTmpX );
426 7464 : cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
427 7464 : cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
428 7464 : cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
429 :
430 7464 : aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
431 7464 : aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
432 7464 : aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
433 7464 : pWriteAccess->SetPixel( y, x, aColRes );
434 : }
435 : }
436 2 : }
437 : }
438 : }
439 : else // scaleByAveraging
440 : {
441 : double aSumRed, aSumGreen, aSumBlue, aCount;
442 0 : BitmapColor aColor;
443 0 : BitmapColor aResultColor;
444 :
445 0 : for( y = 0; y < aTargetHeight; y++ )
446 : {
447 0 : nSinY = pSinY[ y ];
448 0 : nCosY = pCosY[ y ];
449 :
450 0 : for( x = 0; x < aTargetWidth; x++ )
451 : {
452 0 : double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
453 0 : double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
454 :
455 0 : if ( bHMirr )
456 0 : aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
457 0 : if ( bVMirr )
458 0 : aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
459 :
460 0 : if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
461 : ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
462 : {
463 0 : double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
464 0 : double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
465 :
466 0 : int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
467 0 : int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
468 :
469 0 : double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
470 0 : double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
471 :
472 0 : int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
473 0 : int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
474 :
475 0 : aSumRed = aSumGreen = aSumBlue = 0.0;
476 0 : aCount = 0;
477 :
478 0 : for (int yIn = yStart; yIn <= yEnd; yIn++)
479 : {
480 0 : for (int xIn = xStart; xIn <= xEnd; xIn++)
481 : {
482 0 : aColor = pReadAccess->GetPixel( yIn, xIn );
483 :
484 0 : if( pReadAccess->HasPalette() )
485 0 : aColor = pReadAccess->GetPaletteColor( aColor );
486 :
487 0 : aSumRed += aColor.GetRed();
488 0 : aSumGreen += aColor.GetGreen();
489 0 : aSumBlue += aColor.GetBlue();
490 :
491 0 : aCount++;
492 : }
493 : }
494 :
495 0 : aResultColor.SetRed( MinMax( aSumRed / aCount, 0, 255) );
496 0 : aResultColor.SetGreen( MinMax( aSumGreen / aCount, 0, 255) );
497 0 : aResultColor.SetBlue( MinMax( aSumBlue / aCount, 0, 255) );
498 :
499 0 : pWriteAccess->SetPixel( y, x, aResultColor );
500 : }
501 : }
502 0 : }
503 : }
504 :
505 4 : aOutBmp.ReleaseAccess( pWriteAccess );
506 4 : bRet = true;
507 : }
508 :
509 4 : aBmp.ReleaseAccess( pReadAccess );
510 : }
511 :
512 : // mask processing
513 4 : if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 0 && nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
514 : {
515 1 : bRet = false;
516 :
517 1 : if( rBmpEx.IsAlpha() )
518 : {
519 0 : AlphaMask aAlpha( rBmpEx.GetAlpha() );
520 0 : AlphaMask aOutAlpha;
521 :
522 0 : pReadAccess = aAlpha.AcquireReadAccess();
523 :
524 0 : if( pReadAccess )
525 : {
526 0 : aOutAlpha = AlphaMask( Size( aTargetWidth, aTargetHeight ) );
527 0 : pWriteAccess = aOutAlpha.AcquireWriteAccess();
528 :
529 0 : if( pWriteAccess )
530 : {
531 0 : if( pReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
532 0 : pWriteAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
533 : {
534 0 : if ( !scaleByAveraging )
535 : {
536 : Scanline pLine0, pLine1, pLineW;
537 :
538 0 : for( nY = 0; nY < aTargetHeight; nY++ )
539 : {
540 0 : nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
541 0 : pLineW = pWriteAccess->GetScanline( nY );
542 :
543 0 : for( nX = 0; nX < aTargetWidth; nX++ )
544 : {
545 0 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
546 0 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
547 :
548 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
549 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
550 : {
551 0 : nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
552 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
553 :
554 0 : pLine0 = pReadAccess->GetScanline( nTmpY++ );
555 0 : pLine1 = pReadAccess->GetScanline( nTmpY );
556 :
557 0 : const long nAlpha0 = pLine0[ nTmpX ];
558 0 : const long nAlpha2 = pLine1[ nTmpX++ ];
559 0 : const long nAlpha1 = pLine0[ nTmpX ];
560 0 : const long nAlpha3 = pLine1[ nTmpX ];
561 0 : const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
562 0 : const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
563 :
564 0 : *pLineW++ = MAP( n0, n1, nTmpFY );
565 : }
566 : else
567 0 : *pLineW++ = 255;
568 : }
569 : }
570 : }
571 : else // scaleByAveraging
572 : {
573 0 : const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
574 0 : BitmapColor aResultColor( 0 );
575 : double aSum, aCount;
576 :
577 0 : for( y = 0; y < aTargetHeight; y++ )
578 : {
579 0 : nSinY = pSinY[ y ];
580 0 : nCosY = pCosY[ y ];
581 :
582 0 : for( x = 0; x < aTargetWidth; x++ )
583 : {
584 :
585 0 : double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
586 0 : double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
587 :
588 0 : if ( bHMirr )
589 0 : aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
590 0 : if ( bVMirr )
591 0 : aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
592 :
593 0 : if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
594 : ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
595 : {
596 0 : double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
597 0 : double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
598 :
599 0 : int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
600 0 : int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
601 :
602 0 : double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
603 0 : double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
604 :
605 0 : int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
606 0 : int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
607 :
608 0 : aSum = 0.0;
609 0 : aCount = 0;
610 :
611 0 : for (int yIn = yStart; yIn <= yEnd; yIn++)
612 : {
613 0 : for (int xIn = xStart; xIn <= xEnd; xIn++)
614 : {
615 0 : aSum += pReadAccess->GetPixel( yIn, xIn ).GetIndex();
616 0 : aCount++;
617 : }
618 : }
619 0 : aResultColor.SetIndex( MinMax( aSum / aCount, 0, 255) );
620 0 : pWriteAccess->SetPixel( y, x, aResultColor );
621 : }
622 : else
623 : {
624 0 : pWriteAccess->SetPixel( y, x, aTrans );
625 : }
626 : }
627 0 : }
628 : }
629 : }
630 : else
631 : {
632 0 : const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
633 0 : BitmapColor aAlphaVal( 0 );
634 :
635 0 : for( nY = 0; nY < aTargetHeight; nY++ )
636 : {
637 0 : nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
638 :
639 0 : for( nX = 0; nX < aTargetWidth; nX++ )
640 : {
641 0 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
642 0 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
643 :
644 0 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
645 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
646 : {
647 0 : nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
648 0 : nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
649 :
650 0 : const long nAlpha0 = pReadAccess->GetPixel( nTmpY, nTmpX ).GetIndex();
651 0 : const long nAlpha1 = pReadAccess->GetPixel( nTmpY, ++nTmpX ).GetIndex();
652 0 : const long nAlpha3 = pReadAccess->GetPixel( ++nTmpY, nTmpX ).GetIndex();
653 0 : const long nAlpha2 = pReadAccess->GetPixel( nTmpY, --nTmpX ).GetIndex();
654 0 : const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
655 0 : const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
656 :
657 0 : aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
658 0 : pWriteAccess->SetPixel( nY, nX, aAlphaVal );
659 : }
660 : else
661 0 : pWriteAccess->SetPixel( nY, nX, aTrans );
662 : }
663 0 : }
664 : }
665 :
666 0 : aOutAlpha.ReleaseAccess( pWriteAccess );
667 0 : bRet = sal_True;
668 : }
669 :
670 0 : aAlpha.ReleaseAccess( pReadAccess );
671 : }
672 :
673 0 : if( bRet )
674 0 : rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
675 : }
676 : else
677 : {
678 1 : Bitmap aOutMsk( Size( aTargetWidth, aTargetHeight ), 1 );
679 1 : pWriteAccess = aOutMsk.AcquireWriteAccess();
680 :
681 1 : if( pWriteAccess )
682 : {
683 1 : Bitmap aMsk( rBmpEx.GetMask() );
684 1 : const BitmapColor aB( pWriteAccess->GetBestMatchingColor( Color( COL_BLACK ) ) );
685 1 : const BitmapColor aW( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
686 1 : BitmapReadAccess* pMAcc = NULL;
687 :
688 1 : if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
689 : {
690 1 : long* pMapLX = new long[ aUnrotatedWidth ];
691 1 : long* pMapLY = new long[ aUnrotatedHeight ];
692 1 : BitmapColor aTestB;
693 :
694 1 : if( pMAcc )
695 1 : aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
696 :
697 : // create new horizontal mapping table
698 698 : for( nX = 0UL; nX < aUnrotatedWidth; nX++ )
699 697 : pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576. );
700 :
701 : // create new vertical mapping table
702 96 : for( nY = 0UL; nY < aUnrotatedHeight; nY++ )
703 95 : pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576. );
704 :
705 : // do mask rotation
706 96 : for( nY = 0; nY < aTargetHeight; nY++ )
707 : {
708 95 : nSinY = pSinY[ nY ];
709 95 : nCosY = pCosY[ nY ];
710 :
711 66310 : for( nX = 0; nX < aTargetWidth; nX++ )
712 : {
713 66215 : nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
714 66215 : nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
715 :
716 66215 : if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
717 : ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
718 : {
719 132430 : if( pMAcc )
720 : {
721 66215 : if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
722 60639 : pWriteAccess->SetPixel( nY, nX, aB );
723 : else
724 5576 : pWriteAccess->SetPixel( nY, nX, aW );
725 : }
726 : else
727 0 : pWriteAccess->SetPixel( nY, nX, aB );
728 : }
729 : else
730 0 : pWriteAccess->SetPixel( nY, nX, aW );
731 : }
732 : }
733 :
734 1 : delete[] pMapLX;
735 1 : delete[] pMapLY;
736 :
737 1 : if( pMAcc )
738 1 : aMsk.ReleaseAccess( pMAcc );
739 :
740 1 : bRet = sal_True;
741 : }
742 :
743 1 : aOutMsk.ReleaseAccess( pWriteAccess );
744 : }
745 :
746 1 : if( bRet )
747 1 : rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
748 : }
749 :
750 1 : if( !bRet )
751 0 : rOutBmpEx = aOutBmp;
752 : }
753 : else
754 3 : rOutBmpEx = aOutBmp;
755 :
756 4 : delete[] pSinX;
757 4 : delete[] pCosX;
758 4 : delete[] pSinY;
759 4 : delete[] pCosY;
760 :
761 4 : delete[] pMapIX;
762 4 : delete[] pMapFX;
763 4 : delete[] pMapIY;
764 4 : delete[] pMapFY;
765 :
766 4 : return bRet;
767 : }
768 :
769 7 : sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
770 : const Point& rPoint, const Size& rSize,
771 : const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes,
772 : const sal_uLong /*nFlags*/, BitmapEx* pBmpEx )
773 : {
774 7 : sal_uInt16 nRot10 = rAttributes.GetRotation() % 3600;
775 :
776 7 : Point aOutputPointPix;
777 7 : Size aOutputSizePix;
778 7 : Point aUnrotatedPointPix( pOutputDevice->LogicToPixel( rPoint ) );
779 7 : Size aUnrotatedSizePix( pOutputDevice->LogicToPixel( rSize ) );
780 :
781 7 : bool bRet = false;
782 :
783 7 : if( nRot10 )
784 : {
785 0 : Polygon aPoly( Rectangle( rPoint, rSize ) );
786 0 : aPoly.Rotate( rPoint, nRot10 );
787 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
788 0 : aOutputPointPix = pOutputDevice->LogicToPixel( aRotBoundRect.TopLeft() );
789 0 : aOutputSizePix = pOutputDevice->LogicToPixel( aRotBoundRect.GetSize() );
790 : }
791 : else
792 : {
793 7 : aOutputPointPix = aUnrotatedPointPix;
794 7 : aOutputSizePix = aUnrotatedSizePix;
795 : }
796 :
797 7 : if( aUnrotatedSizePix.Width() && aUnrotatedSizePix.Height() )
798 : {
799 7 : BitmapEx aBmpEx( rBitmapEx );
800 7 : BitmapEx aOutBmpEx;
801 7 : Point aOutPoint;
802 7 : Size aOutSize;
803 7 : const Size& rBmpSzPix = rBitmapEx.GetSizePixel();
804 7 : const long nW = rBmpSzPix.Width();
805 7 : const long nH = rBmpSzPix.Height();
806 7 : long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
807 7 : bool bHMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
808 7 : bool bVMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
809 :
810 : // calculate output sizes
811 7 : if( !pBmpEx )
812 : {
813 0 : Point aPt;
814 0 : Rectangle aOutRect( aPt, pOutputDevice->GetOutputSizePixel() );
815 0 : Rectangle aBmpRect( aOutputPointPix, aOutputSizePix );
816 :
817 0 : if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW )
818 : {
819 0 : const Region aPaintRgn( ( (Window*) pOutputDevice )->GetPaintRegion() );
820 0 : if( !aPaintRgn.IsNull() )
821 0 : aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRgn.GetBoundRect() ) );
822 : }
823 :
824 0 : aOutRect.Intersection( aBmpRect );
825 :
826 0 : if( !aOutRect.IsEmpty() )
827 : {
828 0 : aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() );
829 0 : aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
830 0 : nStartX = aOutRect.Left() - aBmpRect.Left();
831 0 : nStartY = aOutRect.Top() - aBmpRect.Top();
832 0 : nEndX = aOutRect.Right() - aBmpRect.Left();
833 0 : nEndY = aOutRect.Bottom() - aBmpRect.Top();
834 : }
835 : else
836 : {
837 0 : nStartX = -1L; // invalid
838 : }
839 : }
840 : else
841 : {
842 7 : aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
843 7 : aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
844 7 : nStartX = nStartY = 0;
845 7 : nEndX = aOutputSizePix.Width() - 1L;
846 7 : nEndY = aOutputSizePix.Height() - 1L;
847 : }
848 :
849 : // do transformation
850 7 : if( nStartX >= 0L )
851 : {
852 7 : const bool bSimple = ( 1 == nW || 1 == nH );
853 :
854 7 : if( nRot10 )
855 : {
856 0 : if( bSimple )
857 : {
858 0 : bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSizePix );
859 :
860 0 : if( bRet )
861 0 : aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
862 : }
863 : else
864 : {
865 : bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
866 : nRot10, aUnrotatedSizePix,
867 : nStartX, nEndX, nStartY, nEndY,
868 0 : aOutBmpEx );
869 : }
870 : }
871 : else
872 : {
873 7 : if( !bHMirr && !bVMirr && aOutputSizePix == rBmpSzPix )
874 : {
875 3 : aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
876 3 : aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
877 3 : aOutBmpEx = aBmpEx;
878 3 : bRet = true;
879 : }
880 : else
881 : {
882 4 : if( bSimple )
883 : {
884 0 : bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
885 : }
886 : else
887 : {
888 : bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
889 : nRot10, aUnrotatedSizePix,
890 : nStartX, nEndX, nStartY, nEndY,
891 4 : aOutBmpEx );
892 : }
893 : }
894 : }
895 :
896 7 : if( bRet )
897 : {
898 : // Attribute adjustment if neccessary
899 7 : if( rAttributes.IsSpecialDrawMode() || rAttributes.IsAdjusted() || rAttributes.IsTransparent() )
900 0 : ImplAdjust( aOutBmpEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
901 :
902 : // OutDev adjustment if neccessary
903 7 : if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER && pOutputDevice->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
904 0 : aOutBmpEx.Dither( BMP_DITHER_MATRIX );
905 : }
906 : }
907 :
908 : // Create output
909 7 : if( bRet )
910 : {
911 7 : if( !pBmpEx )
912 0 : pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aOutBmpEx );
913 : else
914 : {
915 7 : if( !rAttributes.IsTransparent() && !aOutBmpEx.IsAlpha() )
916 6 : aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aOutBmpEx.GetMask() );
917 :
918 7 : pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, *pBmpEx = aOutBmpEx );
919 : }
920 7 : }
921 : }
922 :
923 7 : return bRet;
924 : }
925 :
926 : // This function checks whether the bitmap is usable for skipping
927 : // mtf rendering by using just this one bitmap (i.e. in case the metafile
928 : // contains just this one pixmap that covers the entire metafile area).
929 0 : static BitmapEx checkMetadataBitmap( const BitmapEx& rBmpEx,
930 : Point rSrcPoint,
931 : Size rSrcSize,
932 : const Point& rDestPoint,
933 : const Size& rDestSize,
934 : const Size& rRefSize,
935 : bool& o_rbNonBitmapActionEncountered )
936 : {
937 : // NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too.
938 0 : BitmapEx aBmpEx;
939 0 : if( rSrcSize == Size())
940 0 : rSrcSize = rBmpEx.GetSizePixel();
941 :
942 0 : if( rDestPoint != Point( 0, 0 ))
943 : { // The pixmap in the metafile has an offset (and so would not cover)
944 : // the entire result -> fall back to mtf rendering.
945 0 : o_rbNonBitmapActionEncountered = true;
946 0 : return aBmpEx;
947 : }
948 0 : if( rDestSize != rRefSize )
949 : { // The pixmap is not fullscale (does not cover the entire metafile area).
950 : // HACK: The code here should refuse to use the bitmap directly
951 : // and fall back to mtf rendering, but there seem to be metafiles
952 : // that do not specify exactly their area (the Windows API requires apps
953 : // the specify it manually, the rectangle is specified as topleft/bottomright
954 : // rather than topleft/size [which may be confusing], and the docs
955 : // on the exact meaning are somewhat confusing as well), so if it turns
956 : // out this metafile really contains just one bitmap and no other painting,
957 : // and if the sizes almost match, just use the pixmap (which will be scaled
958 : // to fit exactly the requested size, so there should not be any actual problem
959 : // caused by this small difference). This will allow caching of the resulting
960 : // (scaled) pixmap, which can make a noticeable performance difference.
961 0 : if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
962 0 : && abs( rDestSize.Width() - rRefSize.Width()) < 5
963 0 : && abs( rDestSize.Height() - rRefSize.Height()) < 5 )
964 : ; // ok, assume it's close enough
965 : else
966 : { // fall back to mtf rendering
967 0 : o_rbNonBitmapActionEncountered = true;
968 0 : return aBmpEx;
969 : }
970 : }
971 :
972 0 : aBmpEx = rBmpEx;
973 :
974 0 : if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
975 0 : rSrcSize != rBmpEx.GetSizePixel() )
976 : {
977 : // crop bitmap to given source rectangle (no
978 : // need to copy and convert the whole bitmap)
979 : const Rectangle aCropRect( rSrcPoint,
980 0 : rSrcSize );
981 0 : aBmpEx.Crop( aCropRect );
982 : }
983 :
984 0 : return aBmpEx;
985 : }
986 :
987 1 : sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut,
988 : const Point& rPt, const Size& rSz,
989 : const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
990 : const sal_uLong /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
991 : {
992 1 : const Size aNewSize( rMtf.GetPrefSize() );
993 :
994 1 : rOutMtf = rMtf;
995 :
996 : // Count bitmap actions, and flag actions that paint, but
997 : // are no bitmaps.
998 1 : sal_Int32 nNumBitmaps(0);
999 1 : bool bNonBitmapActionEncountered(false);
1000 1 : if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
1001 : {
1002 1 : const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
1003 1 : const double fOutWH = (double) rSz.Width() / rSz.Height();
1004 :
1005 1 : const double fScaleX = fOutWH / fGrfWH;
1006 1 : const double fScaleY = 1.0;
1007 :
1008 1 : const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
1009 1 : const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
1010 :
1011 : // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap
1012 : // in grfcache.cxx too.
1013 :
1014 : // Determine whether the metafile basically displays
1015 : // a single bitmap (in which case that bitmap is simply used directly
1016 : // instead of playing the metafile). Note that
1017 : // the solution, as implemented here, is quite suboptimal (the
1018 : // cases where a mtf consisting basically of a single bitmap,
1019 : // that fail to pass the test below, are probably frequent). A
1020 : // better solution would involve FSAA, but that's currently
1021 : // expensive, and might trigger bugs on display drivers, if
1022 : // VDevs get bigger than the actual screen.
1023 : sal_uInt32 nCurPos;
1024 : MetaAction* pAct;
1025 35 : for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
1026 : pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
1027 : {
1028 34 : MetaAction* pModAct = NULL;
1029 34 : switch( pAct->GetType() )
1030 : {
1031 : case META_FONT_ACTION:
1032 : {
1033 : // taking care of font width default if scaling metafile.
1034 1 : MetaFontAction* pA = (MetaFontAction*)pAct;
1035 1 : Font aFont( pA->GetFont() );
1036 1 : if ( !aFont.GetWidth() )
1037 : {
1038 0 : FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
1039 0 : aFont.SetWidth( aFontMetric.GetWidth() );
1040 0 : pModAct = new MetaFontAction( aFont );
1041 1 : }
1042 : }
1043 : // FALLTHROUGH intended
1044 : case META_NULL_ACTION:
1045 : // FALLTHROUGH intended
1046 :
1047 : // OutDev state changes (which don't affect bitmap
1048 : // output)
1049 : case META_LINECOLOR_ACTION:
1050 : // FALLTHROUGH intended
1051 : case META_FILLCOLOR_ACTION:
1052 : // FALLTHROUGH intended
1053 : case META_TEXTCOLOR_ACTION:
1054 : // FALLTHROUGH intended
1055 : case META_TEXTFILLCOLOR_ACTION:
1056 : // FALLTHROUGH intended
1057 : case META_TEXTALIGN_ACTION:
1058 : // FALLTHROUGH intended
1059 : case META_TEXTLINECOLOR_ACTION:
1060 : // FALLTHROUGH intended
1061 : case META_TEXTLINE_ACTION:
1062 : // FALLTHROUGH intended
1063 : case META_PUSH_ACTION:
1064 : // FALLTHROUGH intended
1065 : case META_POP_ACTION:
1066 : // FALLTHROUGH intended
1067 : case META_LAYOUTMODE_ACTION:
1068 : // FALLTHROUGH intended
1069 : case META_TEXTLANGUAGE_ACTION:
1070 : // FALLTHROUGH intended
1071 : case META_COMMENT_ACTION:
1072 30 : break;
1073 :
1074 : // bitmap output methods
1075 : case META_BMP_ACTION:
1076 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1077 : {
1078 0 : MetaBmpAction* pAction = (MetaBmpAction*)pAct;
1079 :
1080 : rOutBmpEx = checkMetadataBitmap(
1081 0 : BitmapEx( pAction->GetBitmap()),
1082 : Point(), Size(),
1083 0 : pOut->LogicToPixel( pAction->GetPoint(),
1084 : rPrefMapMode ),
1085 0 : pAction->GetBitmap().GetSizePixel(),
1086 : rSizePix,
1087 0 : bNonBitmapActionEncountered );
1088 : }
1089 0 : ++nNumBitmaps;
1090 0 : break;
1091 :
1092 : case META_BMPSCALE_ACTION:
1093 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1094 : {
1095 0 : MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
1096 :
1097 : rOutBmpEx = checkMetadataBitmap(
1098 0 : BitmapEx( pAction->GetBitmap()),
1099 : Point(), Size(),
1100 0 : pOut->LogicToPixel( pAction->GetPoint(),
1101 : rPrefMapMode ),
1102 0 : pOut->LogicToPixel( pAction->GetSize(),
1103 : rPrefMapMode ),
1104 : rSizePix,
1105 0 : bNonBitmapActionEncountered );
1106 : }
1107 0 : ++nNumBitmaps;
1108 0 : break;
1109 :
1110 : case META_BMPSCALEPART_ACTION:
1111 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1112 : {
1113 0 : MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
1114 :
1115 : rOutBmpEx = checkMetadataBitmap(
1116 0 : BitmapEx( pAction->GetBitmap() ),
1117 0 : pAction->GetSrcPoint(),
1118 0 : pAction->GetSrcSize(),
1119 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
1120 : rPrefMapMode ),
1121 0 : pOut->LogicToPixel( pAction->GetDestSize(),
1122 : rPrefMapMode ),
1123 : rSizePix,
1124 0 : bNonBitmapActionEncountered );
1125 : }
1126 0 : ++nNumBitmaps;
1127 0 : break;
1128 :
1129 : case META_BMPEX_ACTION:
1130 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1131 : {
1132 0 : MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
1133 :
1134 : rOutBmpEx = checkMetadataBitmap(
1135 0 : pAction->GetBitmapEx(),
1136 : Point(), Size(),
1137 0 : pOut->LogicToPixel( pAction->GetPoint(),
1138 : rPrefMapMode ),
1139 0 : pAction->GetBitmapEx().GetSizePixel(),
1140 : rSizePix,
1141 0 : bNonBitmapActionEncountered );
1142 : }
1143 0 : ++nNumBitmaps;
1144 0 : break;
1145 :
1146 : case META_BMPEXSCALE_ACTION:
1147 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1148 : {
1149 0 : MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
1150 :
1151 : rOutBmpEx = checkMetadataBitmap(
1152 0 : pAction->GetBitmapEx(),
1153 : Point(), Size(),
1154 0 : pOut->LogicToPixel( pAction->GetPoint(),
1155 : rPrefMapMode ),
1156 0 : pOut->LogicToPixel( pAction->GetSize(),
1157 : rPrefMapMode ),
1158 : rSizePix,
1159 0 : bNonBitmapActionEncountered );
1160 : }
1161 0 : ++nNumBitmaps;
1162 0 : break;
1163 :
1164 : case META_BMPEXSCALEPART_ACTION:
1165 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
1166 : {
1167 0 : MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
1168 :
1169 0 : rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(),
1170 0 : pAction->GetSrcPoint(),
1171 0 : pAction->GetSrcSize(),
1172 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
1173 : rPrefMapMode ),
1174 0 : pOut->LogicToPixel( pAction->GetDestSize(),
1175 : rPrefMapMode ),
1176 : rSizePix,
1177 0 : bNonBitmapActionEncountered );
1178 : }
1179 0 : ++nNumBitmaps;
1180 0 : break;
1181 :
1182 : // these actions actually output something (that's
1183 : // different from a bitmap)
1184 : case META_RASTEROP_ACTION:
1185 1 : if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
1186 1 : break;
1187 : // FALLTHROUGH intended
1188 : case META_PIXEL_ACTION:
1189 : // FALLTHROUGH intended
1190 : case META_POINT_ACTION:
1191 : // FALLTHROUGH intended
1192 : case META_LINE_ACTION:
1193 : // FALLTHROUGH intended
1194 : case META_RECT_ACTION:
1195 : // FALLTHROUGH intended
1196 : case META_ROUNDRECT_ACTION:
1197 : // FALLTHROUGH intended
1198 : case META_ELLIPSE_ACTION:
1199 : // FALLTHROUGH intended
1200 : case META_ARC_ACTION:
1201 : // FALLTHROUGH intended
1202 : case META_PIE_ACTION:
1203 : // FALLTHROUGH intended
1204 : case META_CHORD_ACTION:
1205 : // FALLTHROUGH intended
1206 : case META_POLYLINE_ACTION:
1207 : // FALLTHROUGH intended
1208 : case META_POLYGON_ACTION:
1209 : // FALLTHROUGH intended
1210 : case META_POLYPOLYGON_ACTION:
1211 : // FALLTHROUGH intended
1212 :
1213 : case META_TEXT_ACTION:
1214 : // FALLTHROUGH intended
1215 : case META_TEXTARRAY_ACTION:
1216 : // FALLTHROUGH intended
1217 : case META_STRETCHTEXT_ACTION:
1218 : // FALLTHROUGH intended
1219 : case META_TEXTRECT_ACTION:
1220 : // FALLTHROUGH intended
1221 :
1222 : case META_MASK_ACTION:
1223 : // FALLTHROUGH intended
1224 : case META_MASKSCALE_ACTION:
1225 : // FALLTHROUGH intended
1226 : case META_MASKSCALEPART_ACTION:
1227 : // FALLTHROUGH intended
1228 :
1229 : case META_GRADIENT_ACTION:
1230 : // FALLTHROUGH intended
1231 : case META_HATCH_ACTION:
1232 : // FALLTHROUGH intended
1233 : case META_WALLPAPER_ACTION:
1234 : // FALLTHROUGH intended
1235 :
1236 : case META_TRANSPARENT_ACTION:
1237 : // FALLTHROUGH intended
1238 : case META_EPS_ACTION:
1239 : // FALLTHROUGH intended
1240 : case META_FLOATTRANSPARENT_ACTION:
1241 : // FALLTHROUGH intended
1242 : case META_GRADIENTEX_ACTION:
1243 : // FALLTHROUGH intended
1244 :
1245 : // OutDev state changes that _do_ affect bitmap
1246 : // output
1247 : case META_CLIPREGION_ACTION:
1248 : // FALLTHROUGH intended
1249 : case META_ISECTRECTCLIPREGION_ACTION:
1250 : // FALLTHROUGH intended
1251 : case META_ISECTREGIONCLIPREGION_ACTION:
1252 : // FALLTHROUGH intended
1253 : case META_MOVECLIPREGION_ACTION:
1254 : // FALLTHROUGH intended
1255 :
1256 : case META_MAPMODE_ACTION:
1257 : // FALLTHROUGH intended
1258 : case META_REFPOINT_ACTION:
1259 : // FALLTHROUGH intended
1260 : default:
1261 3 : bNonBitmapActionEncountered = true;
1262 3 : break;
1263 : }
1264 34 : if ( pModAct )
1265 : {
1266 0 : rOutMtf.ReplaceAction( pModAct, nCurPos );
1267 0 : pAct->Delete();
1268 : }
1269 : else
1270 : {
1271 34 : if( pAct->GetRefCount() > 1 )
1272 : {
1273 34 : rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
1274 34 : pAct->Delete();
1275 : }
1276 : else
1277 0 : pModAct = pAct;
1278 : }
1279 34 : pModAct->Scale( fScaleX, fScaleY );
1280 : }
1281 1 : rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
1282 2 : FRound( aNewSize.Height() * fScaleY ) ) );
1283 : }
1284 :
1285 1 : if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
1286 : {
1287 1 : if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
1288 0 : ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
1289 :
1290 1 : ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
1291 1 : rOutBmpEx = BitmapEx();
1292 : }
1293 :
1294 1 : return sal_True;
1295 : }
1296 :
1297 1 : void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1298 : {
1299 1 : GraphicAttr aAttr( rAttr );
1300 :
1301 1 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1302 : {
1303 0 : switch( aAttr.GetDrawMode() )
1304 : {
1305 : case( GRAPHICDRAWMODE_MONO ):
1306 0 : rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1307 0 : break;
1308 :
1309 : case( GRAPHICDRAWMODE_GREYS ):
1310 0 : rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1311 0 : break;
1312 :
1313 : case( GRAPHICDRAWMODE_WATERMARK ):
1314 : {
1315 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1316 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1317 : }
1318 0 : break;
1319 :
1320 : default:
1321 0 : break;
1322 : }
1323 : }
1324 :
1325 1 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1326 : {
1327 0 : rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1328 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1329 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1330 : }
1331 :
1332 1 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1333 : {
1334 1 : rBmpEx.Mirror( aAttr.GetMirrorFlags() );
1335 : }
1336 :
1337 1 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1338 : {
1339 0 : rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
1340 : }
1341 :
1342 1 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1343 : {
1344 0 : AlphaMask aAlpha;
1345 0 : sal_uInt8 cTrans = aAttr.GetTransparency();
1346 :
1347 0 : if( !rBmpEx.IsTransparent() )
1348 0 : aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
1349 0 : else if( !rBmpEx.IsAlpha() )
1350 : {
1351 0 : aAlpha = rBmpEx.GetMask();
1352 0 : aAlpha.Replace( 0, cTrans );
1353 : }
1354 : else
1355 : {
1356 0 : aAlpha = rBmpEx.GetAlpha();
1357 0 : BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
1358 :
1359 0 : if( pA )
1360 : {
1361 0 : sal_uLong nTrans = cTrans, nNewTrans;
1362 0 : const long nWidth = pA->Width(), nHeight = pA->Height();
1363 :
1364 0 : if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1365 : {
1366 0 : for( long nY = 0; nY < nHeight; nY++ )
1367 : {
1368 0 : Scanline pAScan = pA->GetScanline( nY );
1369 :
1370 0 : for( long nX = 0; nX < nWidth; nX++ )
1371 : {
1372 0 : nNewTrans = nTrans + *pAScan;
1373 0 : *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
1374 : }
1375 : }
1376 : }
1377 : else
1378 : {
1379 0 : BitmapColor aAlphaValue( 0 );
1380 :
1381 0 : for( long nY = 0; nY < nHeight; nY++ )
1382 : {
1383 0 : for( long nX = 0; nX < nWidth; nX++ )
1384 : {
1385 0 : nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
1386 0 : aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
1387 0 : pA->SetPixel( nY, nX, aAlphaValue );
1388 : }
1389 0 : }
1390 : }
1391 :
1392 0 : aAlpha.ReleaseAccess( pA );
1393 : }
1394 : }
1395 :
1396 0 : rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
1397 1 : }
1398 1 : }
1399 :
1400 0 : void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1401 : {
1402 0 : GraphicAttr aAttr( rAttr );
1403 :
1404 0 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1405 : {
1406 0 : switch( aAttr.GetDrawMode() )
1407 : {
1408 : case( GRAPHICDRAWMODE_MONO ):
1409 0 : rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
1410 0 : break;
1411 :
1412 : case( GRAPHICDRAWMODE_GREYS ):
1413 0 : rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
1414 0 : break;
1415 :
1416 : case( GRAPHICDRAWMODE_WATERMARK ):
1417 : {
1418 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1419 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1420 : }
1421 0 : break;
1422 :
1423 : default:
1424 0 : break;
1425 : }
1426 : }
1427 :
1428 0 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1429 : {
1430 0 : rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1431 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1432 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1433 : }
1434 :
1435 0 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1436 : {
1437 0 : rMtf.Mirror( aAttr.GetMirrorFlags() );
1438 : }
1439 :
1440 0 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1441 : {
1442 0 : rMtf.Rotate( aAttr.GetRotation() );
1443 : }
1444 :
1445 0 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1446 : {
1447 : OSL_FAIL( "Missing implementation: Mtf-Transparency" );
1448 0 : }
1449 0 : }
1450 :
1451 0 : void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1452 : {
1453 0 : GraphicAttr aAttr( rAttr );
1454 :
1455 0 : if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1456 : {
1457 0 : switch( aAttr.GetDrawMode() )
1458 : {
1459 : case( GRAPHICDRAWMODE_MONO ):
1460 0 : rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1461 0 : break;
1462 :
1463 : case( GRAPHICDRAWMODE_GREYS ):
1464 0 : rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
1465 0 : break;
1466 :
1467 : case( GRAPHICDRAWMODE_WATERMARK ):
1468 : {
1469 0 : aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1470 0 : aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1471 : }
1472 0 : break;
1473 :
1474 : default:
1475 0 : break;
1476 : }
1477 : }
1478 :
1479 0 : if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1480 : {
1481 0 : rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1482 0 : aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1483 0 : aAttr.GetGamma(), aAttr.IsInvert() );
1484 : }
1485 :
1486 0 : if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1487 : {
1488 0 : rAnimation.Mirror( aAttr.GetMirrorFlags() );
1489 : }
1490 :
1491 0 : if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1492 : {
1493 : OSL_FAIL( "Missing implementation: Animation-Rotation" );
1494 : }
1495 :
1496 0 : if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1497 : {
1498 : OSL_FAIL( "Missing implementation: Animation-Transparency" );
1499 0 : }
1500 0 : }
1501 :
1502 2 : void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1503 : const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1504 : {
1505 2 : sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
1506 2 : Point aOutPt( rPt );
1507 2 : Size aOutSz( rSz );
1508 :
1509 2 : if( nRot10 )
1510 : {
1511 0 : Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1512 :
1513 0 : aPoly.Rotate( aOutPt, nRot10 );
1514 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1515 0 : aOutPt = aRotBoundRect.TopLeft();
1516 0 : aOutSz = aRotBoundRect.GetSize();
1517 : }
1518 :
1519 2 : pOut->Push( PUSH_CLIPREGION );
1520 2 : pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1521 :
1522 2 : ( (GDIMetaFile&) rMtf ).WindStart();
1523 2 : ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1524 2 : ( (GDIMetaFile&) rMtf ).WindStart();
1525 :
1526 2 : pOut->Pop();
1527 2 : }
1528 :
1529 : struct ImplTileInfo
1530 : {
1531 0 : ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1532 :
1533 : Point aTileTopLeft; // top, left position of the rendered tile
1534 : Point aNextTileTopLeft; // top, left position for next recursion
1535 : // level's tile
1536 : Size aTileSizePixel; // size of the generated tile (might
1537 : // differ from
1538 : // aNextTileTopLeft-aTileTopLeft, because
1539 : // this is nExponent*prevTileSize. The
1540 : // generated tile is always nExponent
1541 : // times the previous tile, such that it
1542 : // can be used in the next stage. The
1543 : // required area coverage is often
1544 : // less. The extraneous area covered is
1545 : // later overwritten by the next stage)
1546 : int nTilesEmptyX; // number of original tiles empty right of
1547 : // this tile. This counts from
1548 : // aNextTileTopLeft, i.e. the additional
1549 : // area covered by aTileSizePixel is not
1550 : // considered here. This is for
1551 : // unification purposes, as the iterative
1552 : // calculation of the next level's empty
1553 : // tiles has to be based on this value.
1554 : int nTilesEmptyY; // as above, for Y
1555 : };
1556 :
1557 :
1558 0 : bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
1559 : int nNumTilesX, int nNumTilesY,
1560 : const Size& rTileSizePixel,
1561 : const GraphicAttr* pAttr, sal_uLong nFlags )
1562 : {
1563 0 : if( nExponent <= 1 )
1564 0 : return false;
1565 :
1566 : // determine MSB factor
1567 0 : int nMSBFactor( 1 );
1568 0 : while( nNumTilesX / nMSBFactor != 0 ||
1569 : nNumTilesY / nMSBFactor != 0 )
1570 : {
1571 0 : nMSBFactor *= nExponent;
1572 : }
1573 :
1574 : // one less
1575 0 : nMSBFactor /= nExponent;
1576 :
1577 0 : ImplTileInfo aTileInfo;
1578 :
1579 : // #105229# Switch off mapping (converting to logic and back to
1580 : // pixel might cause roundoff errors)
1581 0 : sal_Bool bOldMap( rVDev.IsMapModeEnabled() );
1582 0 : rVDev.EnableMapMode( sal_False );
1583 :
1584 : bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
1585 0 : nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
1586 :
1587 0 : rVDev.EnableMapMode( bOldMap );
1588 :
1589 0 : return bRet;
1590 : }
1591 :
1592 : // define for debug drawings
1593 : //#define DBG_TEST
1594 :
1595 : // see header comment. this works similar to base conversion of a
1596 : // number, i.e. if the exponent is 10, then the number for every tile
1597 : // size is given by the decimal place of the corresponding decimal
1598 : // representation.
1599 0 : bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
1600 : int nNumOrigTilesX, int nNumOrigTilesY,
1601 : int nRemainderTilesX, int nRemainderTilesY,
1602 : const Size& rTileSizePixel, const GraphicAttr* pAttr,
1603 : sal_uLong nFlags, ImplTileInfo& rTileInfo )
1604 : {
1605 : // gets loaded with our tile bitmap
1606 0 : GraphicObject aTmpGraphic;
1607 :
1608 : // stores a flag that renders the zero'th tile position
1609 : // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
1610 : // recursion stack. All other position already have that tile
1611 : // rendered, because the lower levels painted their generated tile
1612 : // there.
1613 0 : bool bNoFirstTileDraw( false );
1614 :
1615 : // what's left when we're done with our tile size
1616 0 : const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
1617 0 : const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
1618 :
1619 : // gets filled out from the recursive call with info of what's
1620 : // been generated
1621 0 : ImplTileInfo aTileInfo;
1622 :
1623 : // current output position while drawing
1624 0 : Point aCurrPos;
1625 : int nX, nY;
1626 :
1627 : // check for recursion's end condition: LSB place reached?
1628 0 : if( nMSBFactor == 1 )
1629 : {
1630 0 : aTmpGraphic = *this;
1631 :
1632 : // set initial tile size -> orig size
1633 0 : aTileInfo.aTileSizePixel = rTileSizePixel;
1634 0 : aTileInfo.nTilesEmptyX = nNumOrigTilesX;
1635 0 : aTileInfo.nTilesEmptyY = nNumOrigTilesY;
1636 : }
1637 0 : else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
1638 : nNumOrigTilesX, nNumOrigTilesY,
1639 : nNewRemainderX, nNewRemainderY,
1640 0 : rTileSizePixel, pAttr, nFlags, aTileInfo ) )
1641 : {
1642 : // extract generated tile -> see comment on the first loop below
1643 0 : BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
1644 :
1645 0 : aTmpGraphic = GraphicObject( aTileBitmap );
1646 :
1647 : // fill stripes left over from upstream levels:
1648 : //
1649 : // x0000
1650 : // 0
1651 : // 0
1652 : // 0
1653 : // 0
1654 : //
1655 : // where x denotes the place filled by our recursive predecessors
1656 :
1657 : // check whether we have to fill stripes here. Although not
1658 : // obvious, there is one case where we can skip this step: if
1659 : // the previous recursion level (the one who filled our
1660 : // aTileInfo) had zero area to fill, then there are no white
1661 : // stripes left, naturally. This happens if the digit
1662 : // associated to that level has a zero, and can be checked via
1663 : // aTileTopLeft==aNextTileTopLeft.
1664 0 : if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
1665 : {
1666 : // now fill one row from aTileInfo.aNextTileTopLeft.X() all
1667 : // the way to the right
1668 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1669 0 : aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
1670 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
1671 : {
1672 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1673 0 : return false;
1674 :
1675 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1676 : }
1677 :
1678 : #ifdef DBG_TEST
1679 : // rVDev.SetFillColor( COL_WHITE );
1680 : rVDev.SetFillColor();
1681 : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1682 : rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
1683 : aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
1684 : aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
1685 : #endif
1686 :
1687 : // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
1688 : // the way to the bottom
1689 0 : aCurrPos.X() = aTileInfo.aTileTopLeft.X();
1690 0 : aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
1691 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
1692 : {
1693 0 : if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1694 0 : return false;
1695 :
1696 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1697 : }
1698 :
1699 : #ifdef DBG_TEST
1700 : rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
1701 : aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
1702 : aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
1703 : #endif
1704 : }
1705 : else
1706 : {
1707 : // Thought that aTileInfo.aNextTileTopLeft tile has always
1708 : // been drawn already, but that's wrong: typically,
1709 : // _parts_ of that tile have been drawn, since the
1710 : // previous level generated the tile there. But when
1711 : // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
1712 : // difference between these two values is missing in the
1713 : // lower right corner of this first tile. So, can do that
1714 : // only here.
1715 0 : bNoFirstTileDraw = true;
1716 0 : }
1717 : }
1718 : else
1719 : {
1720 0 : return false;
1721 : }
1722 :
1723 : // calc number of original tiles in our drawing area without
1724 : // remainder
1725 0 : nRemainderTilesX -= nNewRemainderX;
1726 0 : nRemainderTilesY -= nNewRemainderY;
1727 :
1728 : // fill tile info for calling method
1729 0 : rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
1730 0 : rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
1731 0 : rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
1732 0 : rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
1733 0 : rTileSizePixel.Height()*nMSBFactor*nExponent );
1734 0 : rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
1735 0 : rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
1736 :
1737 : // init output position
1738 0 : aCurrPos = aTileInfo.aNextTileTopLeft;
1739 :
1740 : // fill our drawing area. Fill possibly more, to create the next
1741 : // bigger tile size -> see bitmap extraction above. This does no
1742 : // harm, since everything right or below our actual area is
1743 : // overdrawn by our caller. Just in case we're in the last level,
1744 : // we don't draw beyond the right or bottom border.
1745 0 : for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
1746 : {
1747 0 : aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1748 :
1749 0 : for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
1750 : {
1751 0 : if( bNoFirstTileDraw )
1752 0 : bNoFirstTileDraw = false; // don't draw first tile position
1753 0 : else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1754 0 : return false;
1755 :
1756 0 : aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1757 : }
1758 :
1759 0 : aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
1760 : }
1761 :
1762 : #ifdef DBG_TEST
1763 : // rVDev.SetFillColor( COL_WHITE );
1764 : rVDev.SetFillColor();
1765 : rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
1766 : rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
1767 : (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
1768 : (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
1769 : (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
1770 : #endif
1771 :
1772 0 : return true;
1773 : }
1774 :
1775 0 : bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
1776 : const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
1777 : {
1778 : // how many tiles to generate per recursion step
1779 : enum{ SubdivisionExponent=2 };
1780 :
1781 0 : const MapMode aOutMapMode( pOut->GetMapMode() );
1782 0 : const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
1783 0 : bool bRet( false );
1784 :
1785 : // #i42643# Casting to Int64, to avoid integer overflow for
1786 : // huge-DPI output devices
1787 0 : if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
1788 0 : static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
1789 : static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
1790 : {
1791 : // First combine very small bitmaps into a larger tile
1792 : // ===================================================
1793 :
1794 0 : VirtualDevice aVDev;
1795 0 : const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
1796 0 : const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
1797 :
1798 0 : aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
1799 0 : nNumTilesInCacheY*rSizePixel.Height() ) );
1800 0 : aVDev.SetMapMode( aMapMode );
1801 :
1802 : // draw bitmap content
1803 0 : if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1804 : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1805 : {
1806 0 : BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
1807 :
1808 : // draw alpha content, if any
1809 0 : if( IsTransparent() )
1810 : {
1811 0 : GraphicObject aAlphaGraphic;
1812 :
1813 0 : if( GetGraphic().IsAlpha() )
1814 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
1815 : else
1816 0 : aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
1817 :
1818 0 : if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1819 : nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1820 : {
1821 : // Combine bitmap and alpha/mask
1822 0 : if( GetGraphic().IsAlpha() )
1823 : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1824 0 : AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
1825 : else
1826 : aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1827 0 : aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
1828 0 : }
1829 : }
1830 :
1831 : // paint generated tile
1832 0 : GraphicObject aTmpGraphic( aTileBitmap );
1833 : bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
1834 0 : aTileBitmap.GetSizePixel(),
1835 0 : rOffset, pAttr, nFlags, nTileCacheSize1D );
1836 0 : }
1837 : }
1838 : else
1839 : {
1840 0 : const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
1841 0 : const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
1842 :
1843 : // number of invisible (because out-of-area) tiles
1844 : int nInvisibleTilesX;
1845 : int nInvisibleTilesY;
1846 :
1847 : // round towards -infty for negative offset
1848 0 : if( aOutOffset.Width() < 0 )
1849 0 : nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
1850 : else
1851 0 : nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
1852 :
1853 : // round towards -infty for negative offset
1854 0 : if( aOutOffset.Height() < 0 )
1855 0 : nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
1856 : else
1857 0 : nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
1858 :
1859 : // origin from where to 'virtually' start drawing in pixel
1860 0 : const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
1861 0 : rArea.Top() - rOffset.Height() ) ) );
1862 : // position in pixel from where to really start output
1863 0 : const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
1864 0 : aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
1865 :
1866 0 : pOut->Push( PUSH_CLIPREGION );
1867 0 : pOut->IntersectClipRegion( rArea );
1868 :
1869 : // Paint all tiles
1870 : // ===============
1871 :
1872 : bRet = ImplDrawTiled( *pOut, aOutStart,
1873 0 : (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
1874 0 : (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
1875 0 : rSizePixel, pAttr, nFlags );
1876 :
1877 0 : pOut->Pop();
1878 : }
1879 :
1880 0 : return bRet;
1881 : }
1882 :
1883 0 : bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
1884 : int nNumTilesX, int nNumTilesY,
1885 : const Size& rTileSizePixel, const GraphicAttr* pAttr, sal_uLong nFlags )
1886 : {
1887 0 : Point aCurrPos( rPosPixel );
1888 0 : Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
1889 : int nX, nY;
1890 :
1891 : // #107607# Use logical coordinates for metafile playing, too
1892 0 : bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
1893 0 : bool bRet = false;
1894 :
1895 : // #105229# Switch off mapping (converting to logic and back to
1896 : // pixel might cause roundoff errors)
1897 0 : bool bOldMap( rOut.IsMapModeEnabled() );
1898 :
1899 0 : if( bDrawInPixel )
1900 0 : rOut.EnableMapMode( sal_False );
1901 :
1902 0 : for( nY=0; nY < nNumTilesY; ++nY )
1903 : {
1904 0 : aCurrPos.X() = rPosPixel.X();
1905 :
1906 0 : for( nX=0; nX < nNumTilesX; ++nX )
1907 : {
1908 : // #105229# work with pixel coordinates here, mapping is disabled!
1909 : // #104004# don't disable mapping for metafile recordings
1910 : // #108412# don't quit the loop if one draw fails
1911 :
1912 : // update return value. This method should return true, if
1913 : // at least one of the looped Draws succeeded.
1914 : bRet |= Draw( &rOut,
1915 : bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
1916 : bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
1917 0 : pAttr, nFlags );
1918 :
1919 0 : aCurrPos.X() += rTileSizePixel.Width();
1920 : }
1921 :
1922 0 : aCurrPos.Y() += rTileSizePixel.Height();
1923 : }
1924 :
1925 0 : if( bDrawInPixel )
1926 0 : rOut.EnableMapMode( bOldMap );
1927 :
1928 0 : return bRet;
1929 : }
1930 :
1931 0 : void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
1932 : const GraphicAttr& rAttr,
1933 : const Size& rCropLeftTop,
1934 : const Size& rCropRightBottom,
1935 : const Rectangle& rCropRect,
1936 : const Size& rDstSize,
1937 : sal_Bool bEnlarge ) const
1938 : {
1939 : // #107947# Extracted from svdograf.cxx
1940 :
1941 : // #104115# Crop the bitmap
1942 0 : if( rAttr.IsCropped() )
1943 : {
1944 0 : rBmpEx.Crop( rCropRect );
1945 :
1946 : // #104115# Negative crop sizes mean: enlarge bitmap and pad
1947 0 : if( bEnlarge && (
1948 0 : rCropLeftTop.Width() < 0 ||
1949 0 : rCropLeftTop.Height() < 0 ||
1950 0 : rCropRightBottom.Width() < 0 ||
1951 0 : rCropRightBottom.Height() < 0 ) )
1952 : {
1953 0 : Size aBmpSize( rBmpEx.GetSizePixel() );
1954 0 : sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
1955 0 : sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
1956 0 : sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
1957 0 : sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
1958 :
1959 0 : BitmapEx aBmpEx2;
1960 :
1961 0 : if( rBmpEx.IsTransparent() )
1962 : {
1963 0 : if( rBmpEx.IsAlpha() )
1964 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
1965 : else
1966 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
1967 : }
1968 : else
1969 : {
1970 : // #104115# Generate mask bitmap and init to zero
1971 0 : Bitmap aMask( aBmpSize, 1 );
1972 0 : aMask.Erase( Color(0,0,0) );
1973 :
1974 : // #104115# Always generate transparent bitmap, we need the border transparent
1975 0 : aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
1976 :
1977 : // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
1978 0 : rBmpEx = aBmpEx2;
1979 : }
1980 :
1981 0 : aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
1982 0 : aBmpEx2.Erase( Color(0xFF,0,0,0) );
1983 0 : aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
1984 0 : rBmpEx = aBmpEx2;
1985 : }
1986 : }
1987 :
1988 0 : const Size aSizePixel( rBmpEx.GetSizePixel() );
1989 :
1990 0 : if( rAttr.GetRotation() != 0 && !IsAnimated() )
1991 : {
1992 0 : if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
1993 : {
1994 0 : double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
1995 0 : double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
1996 0 : double fScaleX = 1.0, fScaleY = 1.0;
1997 :
1998 : // always choose scaling to shrink bitmap
1999 0 : if( fSrcWH < fDstWH )
2000 0 : fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
2001 : else
2002 0 : fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
2003 :
2004 0 : rBmpEx.Scale( fScaleX, fScaleY );
2005 : }
2006 : }
2007 0 : }
2008 :
2009 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|