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