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