GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / svtools / source / graphic / grfmgr2.cxx
blob45c368612b2c5974226906d04d329eac8d536e50
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
33 // -----------
34 // - defines -
35 // -----------
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))
41 // ------------------
42 // - GraphicManager -
43 // ------------------
45 GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) :
46 mpCache( new GraphicCache( nCacheSize, nMaxObjCacheSize ) )
50 GraphicManager::~GraphicManager()
52 for( size_t i = 0, n = maObjList.size(); i < n; ++i )
53 maObjList[ i ]->GraphicManagerDestroyed();
55 delete mpCache;
58 void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
60 mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
63 void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
65 mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
68 void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds )
70 mpCache->SetCacheTimeout( nTimeoutSeconds );
73 void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
75 // !!!
78 sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
79 const Size& rSz, const GraphicObject& rObj,
80 const GraphicAttr& rAttr ) const
82 return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
85 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 )
89 Point aPt( rPt );
90 Size aSz( rSz );
91 sal_Bool bRet = sal_False;
93 rCached = sal_False;
95 if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
97 // create output and fill cache
99 if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
100 ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
101 ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
102 !( nFlags & GRFMGR_DRAW_CACHED ) ||
103 ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
105 // simple output of transformed graphic
106 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
108 if( aGraphic.IsSupportedGraphic() )
110 const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
112 if( nRot10 )
114 Polygon aPoly( Rectangle( aPt, aSz ) );
116 aPoly.Rotate( aPt, nRot10 );
117 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
118 aPt = aRotBoundRect.TopLeft();
119 aSz = aRotBoundRect.GetSize();
122 aGraphic.Draw( pOut, aPt, aSz );
125 bRet = sal_True;
128 if( !bRet )
130 // cached/direct drawing
131 if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
132 bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
133 else
134 bRet = rCached = sal_True;
138 return bRet;
141 void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
142 const OString* pID, const GraphicObject* pCopyObj )
144 maObjList.push_back( (GraphicObject*)&rObj );
145 mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
148 void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
150 mpCache->ReleaseGraphicObject( rObj );
151 for( GraphicObjectList_impl::iterator it = maObjList.begin(); it != maObjList.end(); ++it )
153 if ( *it == &rObj ) {
154 maObjList.erase( it );
155 break;
160 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
162 mpCache->GraphicObjectWasSwappedOut( rObj );
165 OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
167 return mpCache->GetUniqueID( rObj );
170 sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
172 return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
175 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
177 mpCache->GraphicObjectWasSwappedIn( rObj );
180 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 )
185 const Graphic& rGraphic = rObj.GetGraphic();
186 sal_Bool bRet = sal_False;
188 if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
190 if( GRAPHIC_BITMAP == rGraphic.GetType() )
192 const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
194 // #i46805# No point in caching a bitmap that is rendered
195 // via RectFill on the OutDev
196 if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
197 mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
199 BitmapEx aDstBmpEx;
201 if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
203 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
204 bRet = sal_True;
208 if( !bRet )
209 bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
211 else
213 const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
215 if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
217 GDIMetaFile aDstMtf;
218 BitmapEx aContainedBmpEx;
220 if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
222 if( !!aContainedBmpEx )
224 // Use bitmap output method, if metafile basically contains only a single
225 // bitmap (allows caching the resulting pixmap).
226 BitmapEx aDstBmpEx;
228 if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
230 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
231 bRet = sal_True;
234 else
236 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
237 bRet = sal_True;
242 if( !bRet )
244 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
246 if( aGraphic.IsSupportedGraphic() )
248 aGraphic.Draw( pOut, rPt, rSz );
249 bRet = sal_True;
255 return bRet;
258 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 )
263 const long aUnrotatedWidth = rUnrotatedSzPix.Width();
264 const long aUnrotatedHeight = rUnrotatedSzPix.Height();
265 const long aBitmapWidth = rBmpEx.GetSizePixel().Width();
266 const long aBitmapHeight = rBmpEx.GetSizePixel().Height();
268 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nTmp;
269 double fTmp;
271 bool bHMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
272 bool bVMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
274 long* pMapIX = new long[ aUnrotatedWidth ];
275 long* pMapFX = new long[ aUnrotatedWidth ];
276 long* pMapIY = new long[ aUnrotatedHeight ];
277 long* pMapFY = new long[ aUnrotatedHeight ];
279 double fRevScaleX;
280 double fRevScaleY;
282 bool scaleByAveraging = false;
283 int x,y;
285 if(aBitmapWidth > 1 && aUnrotatedWidth > 1)
287 fRevScaleX = (double) ( aBitmapWidth - 1 ) / (double)( aUnrotatedWidth - 1 );
288 // create horizontal mapping table
289 for( x = 0, nTmpX = aBitmapWidth - 1L, nTmp = aBitmapWidth - 2L >= 0 ? aBitmapWidth -2L : 0L; x < aUnrotatedWidth; x++ )
291 fTmp = x * fRevScaleX;
293 if( bHMirr )
294 fTmp = nTmpX - fTmp;
296 pMapIX[ x ] = MinMax( fTmp, 0, nTmp );
297 pMapFX[ x ] = (long) ( ( fTmp - pMapIX[ x ] ) * 1048576.0 );
299 scaleByAveraging |= fRevScaleX > 5.0/3.0;
301 else
303 if(aBitmapWidth == 1)
305 fRevScaleX = 1.0 / (double)( aUnrotatedWidth );
306 for ( x = 0; x < aUnrotatedWidth ; x++)
308 pMapIX[x] = 0;
309 pMapFX[x] = 0;
311 scaleByAveraging = true;
313 else
315 fRevScaleX = (double) aBitmapWidth / (double)( aUnrotatedWidth);
316 fTmp = (double)aBitmapWidth / 2.0;
318 pMapIX[ 0 ] = (long)fTmp;
319 pMapFX[ 0 ] = (long)( ( fTmp - pMapIX[ 0 ] ) * 1048576.0 );
320 scaleByAveraging = true;
323 if(aBitmapHeight > 1 && aUnrotatedHeight > 1)
325 fRevScaleY = (double) ( aBitmapHeight - 1 ) / (double)( aUnrotatedHeight - 1 );
326 // create vertical mapping table
327 for( y = 0, nTmpY = aBitmapHeight - 1L, nTmp = aBitmapHeight - 2L >= 0 ? aBitmapHeight - 2L : 0L; y < aUnrotatedHeight; y++ )
329 fTmp = y * fRevScaleY;
331 if( bVMirr )
332 fTmp = nTmpY - fTmp;
334 pMapIY[ y ] = MinMax( fTmp, 0, nTmp );
335 pMapFY[ y ] = (long) ( ( fTmp - pMapIY[ y ] ) * 1048576.0 );
337 scaleByAveraging |= fRevScaleY > 5.0/3.0;
339 else
341 if(aBitmapHeight == 1)
343 fRevScaleY = 1.0 / (double)( aUnrotatedHeight);
344 for (y = 0; y < aUnrotatedHeight; ++y)
346 pMapIY[y] = 0;
347 pMapFY[y] = 0;
349 scaleByAveraging = true;
351 else
353 fRevScaleY = (double) aBitmapHeight / (double)( aUnrotatedHeight);
354 fTmp = (double)aBitmapHeight / 2.0;
356 pMapIY[ 0 ] = (long)fTmp;
357 pMapFY[ 0 ] = (long)( ( fTmp - pMapIY[ 0 ] ) * 1048576.0 );
358 scaleByAveraging = true;
362 Bitmap aBmp( rBmpEx.GetBitmap() );
363 Bitmap aOutBmp;
364 BitmapReadAccess* pReadAccess = aBmp.AcquireReadAccess();
365 BitmapWriteAccess* pWriteAccess;
367 const double fCosAngle = cos( nRot10 * F_PI1800 );
368 const double fSinAngle = sin( nRot10 * F_PI1800 );
369 const long aTargetWidth = nEndX - nStartX + 1L;
370 const long aTargetHeight = nEndY - nStartY + 1L;
371 long* pCosX = new long[ aTargetWidth ];
372 long* pSinX = new long[ aTargetWidth ];
373 long* pCosY = new long[ aTargetHeight ];
374 long* pSinY = new long[ aTargetHeight ];
375 long nUnRotX, nUnRotY, nSinY, nCosY;
376 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
377 bool bRet = false;
379 Polygon aPoly( Rectangle( Point(), rUnrotatedSzPix ) );
380 aPoly.Rotate( Point(), nRot10 );
381 Rectangle aNewBound( aPoly.GetBoundRect() );
383 // create horizontal mapping table
384 for( x = 0, nTmpX = aNewBound.Left() + nStartX; x < aTargetWidth; x++ )
386 pCosX[ x ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
387 pSinX[ x ] = FRound( fSinAngle * fTmp );
390 // create vertical mapping table
391 for( y = 0, nTmpY = aNewBound.Top() + nStartY; y < aTargetHeight; y++ )
393 pCosY[ y ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
394 pSinY[ y ] = FRound( fSinAngle * fTmp );
397 if( pReadAccess )
399 aOutBmp = Bitmap( Size( aTargetWidth, aTargetHeight ), 24 );
400 pWriteAccess = aOutBmp.AcquireWriteAccess();
402 if( pWriteAccess )
404 BitmapColor aColRes;
406 if ( !scaleByAveraging )
408 if( pReadAccess->HasPalette() )
410 for( y = 0; y < aTargetHeight; y++ )
412 nSinY = pSinY[ y ];
413 nCosY = pCosY[ y ];
415 for( x = 0; x < aTargetWidth; x++ )
417 nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
418 nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
420 if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
421 ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
423 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
424 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
426 const BitmapColor& rCol0 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, nTmpX ) );
427 const BitmapColor& rCol1 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, ++nTmpX ) );
428 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
429 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
430 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
432 const BitmapColor& rCol3 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( ++nTmpY, nTmpX ) );
433 const BitmapColor& rCol2 = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( nTmpY, --nTmpX ) );
434 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
435 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
436 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
438 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
439 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
440 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
441 pWriteAccess->SetPixel( y, x, aColRes );
446 else
448 BitmapColor aCol0, aCol1;
450 for( y = 0; y < aTargetHeight; y++ )
452 nSinY = pSinY[ y ];
453 nCosY = pCosY[ y ];
455 for( x = 0; x < aTargetWidth; x++ )
457 nUnRotX = ( pCosX[ x ] - nSinY ) >> 8;
458 nUnRotY = ( pSinX[ x ] + nCosY ) >> 8;
460 if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
461 ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
463 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
464 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
466 aCol0 = pReadAccess->GetPixel( nTmpY, nTmpX );
467 aCol1 = pReadAccess->GetPixel( nTmpY, ++nTmpX );
468 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
469 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
470 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
472 aCol1 = pReadAccess->GetPixel( ++nTmpY, nTmpX );
473 aCol0 = pReadAccess->GetPixel( nTmpY, --nTmpX );
474 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
475 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
476 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
478 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
479 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
480 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
481 pWriteAccess->SetPixel( y, x, aColRes );
487 else // scaleByAveraging
489 double aSumRed, aSumGreen, aSumBlue, aCount;
490 BitmapColor aColor;
491 BitmapColor aResultColor;
493 for( y = 0; y < aTargetHeight; y++ )
495 nSinY = pSinY[ y ];
496 nCosY = pCosY[ y ];
498 for( x = 0; x < aTargetWidth; x++ )
500 double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
501 double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
503 if ( bHMirr )
504 aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
505 if ( bVMirr )
506 aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
508 if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
509 ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
511 double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
512 double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
514 int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
515 int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
517 double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
518 double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
520 int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
521 int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
523 aSumRed = aSumGreen = aSumBlue = 0.0;
524 aCount = 0;
526 for (int yIn = yStart; yIn <= yEnd; yIn++)
528 for (int xIn = xStart; xIn <= xEnd; xIn++)
530 if( pReadAccess->HasPalette() )
531 aColor = pReadAccess->GetPaletteColor( pReadAccess->GetPixelIndex( yIn, xIn ) );
532 else
533 aColor = pReadAccess->GetPixel( yIn, xIn );
535 aSumRed += aColor.GetRed();
536 aSumGreen += aColor.GetGreen();
537 aSumBlue += aColor.GetBlue();
539 aCount++;
543 aResultColor.SetRed( MinMax( aSumRed / aCount, 0, 255) );
544 aResultColor.SetGreen( MinMax( aSumGreen / aCount, 0, 255) );
545 aResultColor.SetBlue( MinMax( aSumBlue / aCount, 0, 255) );
547 pWriteAccess->SetPixel( y, x, aResultColor );
553 aOutBmp.ReleaseAccess( pWriteAccess );
554 bRet = true;
557 aBmp.ReleaseAccess( pReadAccess );
560 // mask processing
561 if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 0 && nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
563 bRet = false;
565 if( rBmpEx.IsAlpha() )
567 AlphaMask aAlpha( rBmpEx.GetAlpha() );
568 AlphaMask aOutAlpha;
570 pReadAccess = aAlpha.AcquireReadAccess();
572 if( pReadAccess )
574 aOutAlpha = AlphaMask( Size( aTargetWidth, aTargetHeight ) );
575 pWriteAccess = aOutAlpha.AcquireWriteAccess();
577 if( pWriteAccess )
579 if( pReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
580 pWriteAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
582 if ( !scaleByAveraging )
584 Scanline pLine0, pLine1, pLineW;
586 for( nY = 0; nY < aTargetHeight; nY++ )
588 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
589 pLineW = pWriteAccess->GetScanline( nY );
591 for( nX = 0; nX < aTargetWidth; nX++ )
593 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
594 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
596 if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
597 ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
599 nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
600 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
602 pLine0 = pReadAccess->GetScanline( nTmpY++ );
603 pLine1 = pReadAccess->GetScanline( nTmpY );
605 const long nAlpha0 = pLine0[ nTmpX ];
606 const long nAlpha2 = pLine1[ nTmpX++ ];
607 const long nAlpha1 = pLine0[ nTmpX ];
608 const long nAlpha3 = pLine1[ nTmpX ];
609 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
610 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
612 *pLineW++ = MAP( n0, n1, nTmpFY );
614 else
615 *pLineW++ = 255;
619 else // scaleByAveraging
621 const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
622 BitmapColor aResultColor( 0 );
623 double aSum, aCount;
625 for( y = 0; y < aTargetHeight; y++ )
627 nSinY = pSinY[ y ];
628 nCosY = pCosY[ y ];
630 for( x = 0; x < aTargetWidth; x++ )
633 double aUnrotatedX = ( pCosX[ x ] - nSinY ) / 256.0;
634 double aUnrotatedY = ( pSinX[ x ] + nCosY ) / 256.0;
636 if ( bHMirr )
637 aUnrotatedX = aUnrotatedWidth - aUnrotatedX - 1;
638 if ( bVMirr )
639 aUnrotatedY = aUnrotatedHeight - aUnrotatedY - 1;
641 if( ( aUnrotatedX >= 0 ) && ( aUnrotatedX < aUnrotatedWidth ) &&
642 ( aUnrotatedY >= 0 ) && ( aUnrotatedY < aUnrotatedHeight ) )
644 double dYStart = ((aUnrotatedY + 0.5) * fRevScaleY) - 0.5;
645 double dYEnd = ((aUnrotatedY + 1.5) * fRevScaleY) - 0.5;
647 int yStart = MinMax( dYStart, 0, aBitmapHeight - 1);
648 int yEnd = MinMax( dYEnd, 0, aBitmapHeight - 1);
650 double dXStart = ((aUnrotatedX + 0.5) * fRevScaleX) - 0.5;
651 double dXEnd = ((aUnrotatedX + 1.5) * fRevScaleX) - 0.5;
653 int xStart = MinMax( dXStart, 0, aBitmapWidth - 1);
654 int xEnd = MinMax( dXEnd, 0, aBitmapWidth - 1);
656 aSum = 0.0;
657 aCount = 0;
659 for (int yIn = yStart; yIn <= yEnd; yIn++)
661 for (int xIn = xStart; xIn <= xEnd; xIn++)
663 aSum += pReadAccess->GetPixel( yIn, xIn ).GetIndex();
664 aCount++;
667 aResultColor.SetIndex( MinMax( aSum / aCount, 0, 255) );
668 pWriteAccess->SetPixel( y, x, aResultColor );
670 else
672 pWriteAccess->SetPixel( y, x, aTrans );
678 else
680 const BitmapColor aTrans( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
681 BitmapColor aAlphaVal( 0 );
683 for( nY = 0; nY < aTargetHeight; nY++ )
685 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
687 for( nX = 0; nX < aTargetWidth; nX++ )
689 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
690 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
692 if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
693 ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
695 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
696 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
698 const long nAlpha0 = pReadAccess->GetPixel( nTmpY, nTmpX ).GetIndex();
699 const long nAlpha1 = pReadAccess->GetPixel( nTmpY, ++nTmpX ).GetIndex();
700 const long nAlpha3 = pReadAccess->GetPixel( ++nTmpY, nTmpX ).GetIndex();
701 const long nAlpha2 = pReadAccess->GetPixel( nTmpY, --nTmpX ).GetIndex();
702 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
703 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
705 aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
706 pWriteAccess->SetPixel( nY, nX, aAlphaVal );
708 else
709 pWriteAccess->SetPixel( nY, nX, aTrans );
714 aOutAlpha.ReleaseAccess( pWriteAccess );
715 bRet = sal_True;
718 aAlpha.ReleaseAccess( pReadAccess );
721 if( bRet )
722 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
724 else
726 Bitmap aOutMsk( Size( aTargetWidth, aTargetHeight ), 1 );
727 pWriteAccess = aOutMsk.AcquireWriteAccess();
729 if( pWriteAccess )
731 Bitmap aMsk( rBmpEx.GetMask() );
732 const BitmapColor aB( pWriteAccess->GetBestMatchingColor( Color( COL_BLACK ) ) );
733 const BitmapColor aW( pWriteAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
734 BitmapReadAccess* pMAcc = NULL;
736 if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
738 long* pMapLX = new long[ aUnrotatedWidth ];
739 long* pMapLY = new long[ aUnrotatedHeight ];
740 BitmapColor aTestB;
742 if( pMAcc )
743 aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
745 // create new horizontal mapping table
746 for( nX = 0UL; nX < aUnrotatedWidth; nX++ )
747 pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576.0 );
749 // create new vertical mapping table
750 for( nY = 0UL; nY < aUnrotatedHeight; nY++ )
751 pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576.0 );
753 // do mask rotation
754 for( nY = 0; nY < aTargetHeight; nY++ )
756 nSinY = pSinY[ nY ];
757 nCosY = pCosY[ nY ];
759 for( nX = 0; nX < aTargetWidth; nX++ )
761 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
762 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
764 if( ( nUnRotX >= 0L ) && ( nUnRotX < aUnrotatedWidth ) &&
765 ( nUnRotY >= 0L ) && ( nUnRotY < aUnrotatedHeight ) )
767 if( pMAcc )
769 if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
770 pWriteAccess->SetPixel( nY, nX, aB );
771 else
772 pWriteAccess->SetPixel( nY, nX, aW );
774 else
775 pWriteAccess->SetPixel( nY, nX, aB );
777 else
778 pWriteAccess->SetPixel( nY, nX, aW );
782 delete[] pMapLX;
783 delete[] pMapLY;
785 if( pMAcc )
786 aMsk.ReleaseAccess( pMAcc );
788 bRet = sal_True;
791 aOutMsk.ReleaseAccess( pWriteAccess );
794 if( bRet )
795 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
798 if( !bRet )
799 rOutBmpEx = aOutBmp;
801 else
802 rOutBmpEx = aOutBmp;
804 delete[] pSinX;
805 delete[] pCosX;
806 delete[] pSinY;
807 delete[] pCosY;
809 delete[] pMapIX;
810 delete[] pMapFX;
811 delete[] pMapIY;
812 delete[] pMapFY;
814 return bRet;
817 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 )
822 sal_uInt16 nRot10 = rAttributes.GetRotation() % 3600;
824 Point aOutputPointPix;
825 Size aOutputSizePix;
826 Point aUnrotatedPointPix( pOutputDevice->LogicToPixel( rPoint ) );
827 Size aUnrotatedSizePix( pOutputDevice->LogicToPixel( rSize ) );
829 bool bRet = false;
831 if( nRot10 )
833 Polygon aPoly( Rectangle( rPoint, rSize ) );
834 aPoly.Rotate( rPoint, nRot10 );
835 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
836 aOutputPointPix = pOutputDevice->LogicToPixel( aRotBoundRect.TopLeft() );
837 aOutputSizePix = pOutputDevice->LogicToPixel( aRotBoundRect.GetSize() );
839 else
841 aOutputPointPix = aUnrotatedPointPix;
842 aOutputSizePix = aUnrotatedSizePix;
845 if( aUnrotatedSizePix.Width() && aUnrotatedSizePix.Height() )
847 BitmapEx aBmpEx( rBitmapEx );
848 BitmapEx aOutBmpEx;
849 Point aOutPoint;
850 Size aOutSize;
851 const Size& rBmpSzPix = rBitmapEx.GetSizePixel();
852 const long nW = rBmpSzPix.Width();
853 const long nH = rBmpSzPix.Height();
854 long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
855 bool bHMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
856 bool bVMirr = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
858 // calculate output sizes
859 if( !pBmpEx )
861 Point aPt;
862 Rectangle aOutRect( aPt, pOutputDevice->GetOutputSizePixel() );
863 Rectangle aBmpRect( aOutputPointPix, aOutputSizePix );
865 if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW )
867 const Region aPaintRgn( ( (Window*) pOutputDevice )->GetPaintRegion() );
868 if( !aPaintRgn.IsNull() )
869 aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRgn.GetBoundRect() ) );
872 aOutRect.Intersection( aBmpRect );
874 if( !aOutRect.IsEmpty() )
876 aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() );
877 aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
878 nStartX = aOutRect.Left() - aBmpRect.Left();
879 nStartY = aOutRect.Top() - aBmpRect.Top();
880 nEndX = aOutRect.Right() - aBmpRect.Left();
881 nEndY = aOutRect.Bottom() - aBmpRect.Top();
883 else
885 nStartX = -1L; // invalid
888 else
890 aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
891 aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
892 nStartX = nStartY = 0;
893 nEndX = aOutputSizePix.Width() - 1L;
894 nEndY = aOutputSizePix.Height() - 1L;
897 // do transformation
898 if( nStartX >= 0L )
900 const bool bSimple = ( 1 == nW || 1 == nH );
902 if( nRot10 )
904 if( bSimple )
906 bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSizePix );
908 if( bRet )
909 aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
911 else
913 bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
914 nRot10, aUnrotatedSizePix,
915 nStartX, nEndX, nStartY, nEndY,
916 aOutBmpEx );
919 else
921 if( !bHMirr && !bVMirr && aOutputSizePix == rBmpSzPix )
923 aOutPoint = pOutputDevice->PixelToLogic( aOutputPointPix );
924 aOutSize = pOutputDevice->PixelToLogic( aOutputSizePix );
925 aOutBmpEx = aBmpEx;
926 bRet = true;
928 else
930 if( bSimple )
932 bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
934 else
936 bRet = ImplCreateRotatedScaled( aBmpEx, rAttributes,
937 nRot10, aUnrotatedSizePix,
938 nStartX, nEndX, nStartY, nEndY,
939 aOutBmpEx );
944 if( bRet )
946 // Attribute adjustment if necessary
947 if( rAttributes.IsSpecialDrawMode() || rAttributes.IsAdjusted() || rAttributes.IsTransparent() )
948 ImplAdjust( aOutBmpEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
950 // OutDev adjustment if necessary
951 if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER && pOutputDevice->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
952 aOutBmpEx.Dither( BMP_DITHER_MATRIX );
956 // Create output
957 if( bRet )
959 if( !pBmpEx )
960 pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aOutBmpEx );
961 else
963 if( !rAttributes.IsTransparent() && !aOutBmpEx.IsAlpha() )
964 aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aOutBmpEx.GetMask() );
966 pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, *pBmpEx = aOutBmpEx );
971 return bRet;
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 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 )
985 // NOTE: If you do changes in this function, change checkMetadataBitmap() in grfcache.cxx too.
986 BitmapEx aBmpEx;
987 if( rSrcSize == Size())
988 rSrcSize = rBmpEx.GetSizePixel();
990 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 o_rbNonBitmapActionEncountered = true;
994 return aBmpEx;
996 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 if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
1010 && abs( rDestSize.Width() - rRefSize.Width()) < 5
1011 && abs( rDestSize.Height() - rRefSize.Height()) < 5 )
1012 ; // ok, assume it's close enough
1013 else
1014 { // fall back to mtf rendering
1015 o_rbNonBitmapActionEncountered = true;
1016 return aBmpEx;
1020 aBmpEx = rBmpEx;
1022 if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
1023 rSrcSize != rBmpEx.GetSizePixel() )
1025 // crop bitmap to given source rectangle (no
1026 // need to copy and convert the whole bitmap)
1027 const Rectangle aCropRect( rSrcPoint,
1028 rSrcSize );
1029 aBmpEx.Crop( aCropRect );
1032 return aBmpEx;
1035 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 )
1040 const Size aNewSize( rMtf.GetPrefSize() );
1042 rOutMtf = rMtf;
1044 // Count bitmap actions, and flag actions that paint, but
1045 // are no bitmaps.
1046 sal_Int32 nNumBitmaps(0);
1047 bool bNonBitmapActionEncountered(false);
1048 if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
1050 const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
1051 const double fOutWH = (double) rSz.Width() / rSz.Height();
1053 const double fScaleX = fOutWH / fGrfWH;
1054 const double fScaleY = 1.0;
1056 const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
1057 const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
1059 // NOTE: If you do changes in this function, check GraphicDisplayCacheEntry::IsCacheableAsBitmap
1060 // in grfcache.cxx too.
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 for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
1074 pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
1076 MetaAction* pModAct = NULL;
1077 switch( pAct->GetType() )
1079 case META_FONT_ACTION:
1081 // taking care of font width default if scaling metafile.
1082 MetaFontAction* pA = (MetaFontAction*)pAct;
1083 Font aFont( pA->GetFont() );
1084 if ( !aFont.GetWidth() )
1086 FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
1087 aFont.SetWidth( aFontMetric.GetWidth() );
1088 pModAct = new MetaFontAction( aFont );
1091 // FALLTHROUGH intended
1092 case META_NULL_ACTION:
1093 // FALLTHROUGH intended
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 break;
1122 // bitmap output methods
1123 case META_BMP_ACTION:
1124 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1126 MetaBmpAction* pAction = (MetaBmpAction*)pAct;
1128 rOutBmpEx = checkMetadataBitmap(
1129 BitmapEx( pAction->GetBitmap()),
1130 Point(), Size(),
1131 pOut->LogicToPixel( pAction->GetPoint(),
1132 rPrefMapMode ),
1133 pAction->GetBitmap().GetSizePixel(),
1134 rSizePix,
1135 bNonBitmapActionEncountered );
1137 ++nNumBitmaps;
1138 break;
1140 case META_BMPSCALE_ACTION:
1141 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1143 MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
1145 rOutBmpEx = checkMetadataBitmap(
1146 BitmapEx( pAction->GetBitmap()),
1147 Point(), Size(),
1148 pOut->LogicToPixel( pAction->GetPoint(),
1149 rPrefMapMode ),
1150 pOut->LogicToPixel( pAction->GetSize(),
1151 rPrefMapMode ),
1152 rSizePix,
1153 bNonBitmapActionEncountered );
1155 ++nNumBitmaps;
1156 break;
1158 case META_BMPSCALEPART_ACTION:
1159 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1161 MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
1163 rOutBmpEx = checkMetadataBitmap(
1164 BitmapEx( pAction->GetBitmap() ),
1165 pAction->GetSrcPoint(),
1166 pAction->GetSrcSize(),
1167 pOut->LogicToPixel( pAction->GetDestPoint(),
1168 rPrefMapMode ),
1169 pOut->LogicToPixel( pAction->GetDestSize(),
1170 rPrefMapMode ),
1171 rSizePix,
1172 bNonBitmapActionEncountered );
1174 ++nNumBitmaps;
1175 break;
1177 case META_BMPEX_ACTION:
1178 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1180 MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
1182 rOutBmpEx = checkMetadataBitmap(
1183 pAction->GetBitmapEx(),
1184 Point(), Size(),
1185 pOut->LogicToPixel( pAction->GetPoint(),
1186 rPrefMapMode ),
1187 pAction->GetBitmapEx().GetSizePixel(),
1188 rSizePix,
1189 bNonBitmapActionEncountered );
1191 ++nNumBitmaps;
1192 break;
1194 case META_BMPEXSCALE_ACTION:
1195 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1197 MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
1199 rOutBmpEx = checkMetadataBitmap(
1200 pAction->GetBitmapEx(),
1201 Point(), Size(),
1202 pOut->LogicToPixel( pAction->GetPoint(),
1203 rPrefMapMode ),
1204 pOut->LogicToPixel( pAction->GetSize(),
1205 rPrefMapMode ),
1206 rSizePix,
1207 bNonBitmapActionEncountered );
1209 ++nNumBitmaps;
1210 break;
1212 case META_BMPEXSCALEPART_ACTION:
1213 if( !nNumBitmaps && !bNonBitmapActionEncountered )
1215 MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
1217 rOutBmpEx = checkMetadataBitmap( pAction->GetBitmapEx(),
1218 pAction->GetSrcPoint(),
1219 pAction->GetSrcSize(),
1220 pOut->LogicToPixel( pAction->GetDestPoint(),
1221 rPrefMapMode ),
1222 pOut->LogicToPixel( pAction->GetDestSize(),
1223 rPrefMapMode ),
1224 rSizePix,
1225 bNonBitmapActionEncountered );
1227 ++nNumBitmaps;
1228 break;
1230 // these actions actually output something (that's
1231 // different from a bitmap)
1232 case META_RASTEROP_ACTION:
1233 if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
1234 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
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
1270 case META_MASK_ACTION:
1271 // FALLTHROUGH intended
1272 case META_MASKSCALE_ACTION:
1273 // FALLTHROUGH intended
1274 case META_MASKSCALEPART_ACTION:
1275 // FALLTHROUGH intended
1277 case META_GRADIENT_ACTION:
1278 // FALLTHROUGH intended
1279 case META_HATCH_ACTION:
1280 // FALLTHROUGH intended
1281 case META_WALLPAPER_ACTION:
1282 // FALLTHROUGH intended
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
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
1304 case META_MAPMODE_ACTION:
1305 // FALLTHROUGH intended
1306 case META_REFPOINT_ACTION:
1307 // FALLTHROUGH intended
1308 default:
1309 bNonBitmapActionEncountered = true;
1310 break;
1312 if ( pModAct )
1314 MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct, nCurPos );
1315 assert(pDeleteAction);
1316 pDeleteAction->Delete();
1318 else
1320 if( pAct->GetRefCount() > 1 )
1322 MetaAction* pDeleteAction = rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
1323 assert(pDeleteAction);
1324 pDeleteAction->Delete();
1326 else
1327 pModAct = pAct;
1329 pModAct->Scale( fScaleX, fScaleY );
1331 rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
1332 FRound( aNewSize.Height() * fScaleY ) ) );
1335 if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
1337 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
1338 ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
1340 ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
1341 rOutBmpEx = BitmapEx();
1344 return sal_True;
1347 void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1349 GraphicAttr aAttr( rAttr );
1351 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1353 switch( aAttr.GetDrawMode() )
1355 case( GRAPHICDRAWMODE_MONO ):
1356 rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1357 break;
1359 case( GRAPHICDRAWMODE_GREYS ):
1360 rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1361 break;
1363 case( GRAPHICDRAWMODE_WATERMARK ):
1365 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1366 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1368 break;
1370 default:
1371 break;
1375 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1377 rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1378 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1379 aAttr.GetGamma(), aAttr.IsInvert() );
1382 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1384 rBmpEx.Mirror( aAttr.GetMirrorFlags() );
1387 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1389 rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
1392 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1394 AlphaMask aAlpha;
1395 sal_uInt8 cTrans = aAttr.GetTransparency();
1397 if( !rBmpEx.IsTransparent() )
1398 aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
1399 else if( !rBmpEx.IsAlpha() )
1401 aAlpha = rBmpEx.GetMask();
1402 aAlpha.Replace( 0, cTrans );
1404 else
1406 aAlpha = rBmpEx.GetAlpha();
1407 BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
1409 if( pA )
1411 sal_uLong nTrans = cTrans, nNewTrans;
1412 const long nWidth = pA->Width(), nHeight = pA->Height();
1414 if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1416 for( long nY = 0; nY < nHeight; nY++ )
1418 Scanline pAScan = pA->GetScanline( nY );
1420 for( long nX = 0; nX < nWidth; nX++ )
1422 nNewTrans = nTrans + *pAScan;
1423 *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
1427 else
1429 BitmapColor aAlphaValue( 0 );
1431 for( long nY = 0; nY < nHeight; nY++ )
1433 for( long nX = 0; nX < nWidth; nX++ )
1435 nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
1436 aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
1437 pA->SetPixel( nY, nX, aAlphaValue );
1442 aAlpha.ReleaseAccess( pA );
1446 rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
1450 void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1452 GraphicAttr aAttr( rAttr );
1454 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1456 switch( aAttr.GetDrawMode() )
1458 case( GRAPHICDRAWMODE_MONO ):
1459 rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
1460 break;
1462 case( GRAPHICDRAWMODE_GREYS ):
1463 rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
1464 break;
1466 case( GRAPHICDRAWMODE_WATERMARK ):
1468 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1469 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1471 break;
1473 default:
1474 break;
1478 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1480 rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1481 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1482 aAttr.GetGamma(), aAttr.IsInvert() );
1485 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1487 rMtf.Mirror( aAttr.GetMirrorFlags() );
1490 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1492 rMtf.Rotate( aAttr.GetRotation() );
1495 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1497 OSL_FAIL( "Missing implementation: Mtf-Transparency" );
1501 void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1503 GraphicAttr aAttr( rAttr );
1505 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1507 switch( aAttr.GetDrawMode() )
1509 case( GRAPHICDRAWMODE_MONO ):
1510 rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1511 break;
1513 case( GRAPHICDRAWMODE_GREYS ):
1514 rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
1515 break;
1517 case( GRAPHICDRAWMODE_WATERMARK ):
1519 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1520 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1522 break;
1524 default:
1525 break;
1529 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1531 rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1532 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1533 aAttr.GetGamma(), aAttr.IsInvert() );
1536 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1538 rAnimation.Mirror( aAttr.GetMirrorFlags() );
1541 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1543 OSL_FAIL( "Missing implementation: Animation-Rotation" );
1546 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1548 OSL_FAIL( "Missing implementation: Animation-Transparency" );
1552 void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1553 const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1555 sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
1556 Point aOutPt( rPt );
1557 Size aOutSz( rSz );
1559 if( nRot10 )
1561 Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1563 aPoly.Rotate( aOutPt, nRot10 );
1564 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1565 aOutPt = aRotBoundRect.TopLeft();
1566 aOutSz = aRotBoundRect.GetSize();
1569 pOut->Push( PUSH_CLIPREGION );
1570 pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1572 ( (GDIMetaFile&) rMtf ).WindStart();
1573 ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1574 ( (GDIMetaFile&) rMtf ).WindStart();
1576 pOut->Pop();
1579 struct ImplTileInfo
1581 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
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
1608 bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
1609 int nNumTilesX, int nNumTilesY,
1610 const Size& rTileSizePixel,
1611 const GraphicAttr* pAttr, sal_uLong nFlags )
1613 if( nExponent <= 1 )
1614 return false;
1616 // determine MSB factor
1617 int nMSBFactor( 1 );
1618 while( nNumTilesX / nMSBFactor != 0 ||
1619 nNumTilesY / nMSBFactor != 0 )
1621 nMSBFactor *= nExponent;
1624 // one less
1625 nMSBFactor /= nExponent;
1627 ImplTileInfo aTileInfo;
1629 // #105229# Switch off mapping (converting to logic and back to
1630 // pixel might cause roundoff errors)
1631 sal_Bool bOldMap( rVDev.IsMapModeEnabled() );
1632 rVDev.EnableMapMode( sal_False );
1634 bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
1635 nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
1637 rVDev.EnableMapMode( bOldMap );
1639 return bRet;
1642 // define for debug drawings
1643 //#define DBG_TEST
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 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 )
1655 // gets loaded with our tile bitmap
1656 GraphicObject aTmpGraphic;
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 bool bNoFirstTileDraw( false );
1665 // what's left when we're done with our tile size
1666 const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
1667 const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
1669 // gets filled out from the recursive call with info of what's
1670 // been generated
1671 ImplTileInfo aTileInfo;
1673 // current output position while drawing
1674 Point aCurrPos;
1675 int nX, nY;
1677 // check for recursion's end condition: LSB place reached?
1678 if( nMSBFactor == 1 )
1680 aTmpGraphic = *this;
1682 // set initial tile size -> orig size
1683 aTileInfo.aTileSizePixel = rTileSizePixel;
1684 aTileInfo.nTilesEmptyX = nNumOrigTilesX;
1685 aTileInfo.nTilesEmptyY = nNumOrigTilesY;
1687 else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
1688 nNumOrigTilesX, nNumOrigTilesY,
1689 nNewRemainderX, nNewRemainderY,
1690 rTileSizePixel, pAttr, nFlags, aTileInfo ) )
1692 // extract generated tile -> see comment on the first loop below
1693 BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
1695 aTmpGraphic = GraphicObject( aTileBitmap );
1697 // fill stripes left over from upstream levels:
1699 // x0000
1700 // 0
1701 // 0
1702 // 0
1703 // 0
1705 // where x denotes the place filled by our recursive predecessors
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 if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
1716 // now fill one row from aTileInfo.aNextTileTopLeft.X() all
1717 // the way to the right
1718 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1719 aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
1720 for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
1722 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1723 return false;
1725 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
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
1737 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
1738 // the way to the bottom
1739 aCurrPos.X() = aTileInfo.aTileTopLeft.X();
1740 aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
1741 for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
1743 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1744 return false;
1746 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
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
1755 else
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 bNoFirstTileDraw = true;
1768 else
1770 return false;
1773 // calc number of original tiles in our drawing area without
1774 // remainder
1775 nRemainderTilesX -= nNewRemainderX;
1776 nRemainderTilesY -= nNewRemainderY;
1778 // fill tile info for calling method
1779 rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
1780 rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
1781 rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
1782 rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
1783 rTileSizePixel.Height()*nMSBFactor*nExponent );
1784 rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
1785 rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
1787 // init output position
1788 aCurrPos = aTileInfo.aNextTileTopLeft;
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 for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
1797 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
1799 for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
1801 if( bNoFirstTileDraw )
1802 bNoFirstTileDraw = false; // don't draw first tile position
1803 else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
1804 return false;
1806 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
1809 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
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
1822 return true;
1825 bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
1826 const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
1828 // how many tiles to generate per recursion step
1829 enum{ SubdivisionExponent=2 };
1831 const MapMode aOutMapMode( pOut->GetMapMode() );
1832 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
1833 bool bRet( false );
1835 // #i42643# Casting to Int64, to avoid integer overflow for
1836 // huge-DPI output devices
1837 if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
1838 static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
1839 static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
1841 // First combine very small bitmaps into a larger tile
1842 // ===================================================
1844 VirtualDevice aVDev;
1845 const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
1846 const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
1848 aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
1849 nNumTilesInCacheY*rSizePixel.Height() ) );
1850 aVDev.SetMapMode( aMapMode );
1852 // draw bitmap content
1853 if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1854 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1856 BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
1858 // draw alpha content, if any
1859 if( IsTransparent() )
1861 GraphicObject aAlphaGraphic;
1863 if( GetGraphic().IsAlpha() )
1864 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
1865 else
1866 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
1868 if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
1869 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
1871 // Combine bitmap and alpha/mask
1872 if( GetGraphic().IsAlpha() )
1873 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1874 AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
1875 else
1876 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
1877 aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
1881 // paint generated tile
1882 GraphicObject aTmpGraphic( aTileBitmap );
1883 bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
1884 aTileBitmap.GetSizePixel(),
1885 rOffset, pAttr, nFlags, nTileCacheSize1D );
1888 else
1890 const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
1891 const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
1893 // number of invisible (because out-of-area) tiles
1894 int nInvisibleTilesX;
1895 int nInvisibleTilesY;
1897 // round towards -infty for negative offset
1898 if( aOutOffset.Width() < 0 )
1899 nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
1900 else
1901 nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
1903 // round towards -infty for negative offset
1904 if( aOutOffset.Height() < 0 )
1905 nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
1906 else
1907 nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
1909 // origin from where to 'virtually' start drawing in pixel
1910 const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
1911 rArea.Top() - rOffset.Height() ) ) );
1912 // position in pixel from where to really start output
1913 const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
1914 aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
1916 pOut->Push( PUSH_CLIPREGION );
1917 pOut->IntersectClipRegion( rArea );
1919 // Paint all tiles
1920 // ===============
1922 bRet = ImplDrawTiled( *pOut, aOutStart,
1923 (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
1924 (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
1925 rSizePixel, pAttr, nFlags );
1927 pOut->Pop();
1930 return bRet;
1933 bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
1934 int nNumTilesX, int nNumTilesY,
1935 const Size& rTileSizePixel, const GraphicAttr* pAttr, sal_uLong nFlags )
1937 Point aCurrPos( rPosPixel );
1938 Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
1939 int nX, nY;
1941 // #107607# Use logical coordinates for metafile playing, too
1942 bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
1943 bool bRet = false;
1945 // #105229# Switch off mapping (converting to logic and back to
1946 // pixel might cause roundoff errors)
1947 bool bOldMap( rOut.IsMapModeEnabled() );
1949 if( bDrawInPixel )
1950 rOut.EnableMapMode( sal_False );
1952 for( nY=0; nY < nNumTilesY; ++nY )
1954 aCurrPos.X() = rPosPixel.X();
1956 for( nX=0; nX < nNumTilesX; ++nX )
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
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 pAttr, nFlags );
1969 aCurrPos.X() += rTileSizePixel.Width();
1972 aCurrPos.Y() += rTileSizePixel.Height();
1975 if( bDrawInPixel )
1976 rOut.EnableMapMode( bOldMap );
1978 return bRet;
1981 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
1989 // #107947# Extracted from svdograf.cxx
1991 // #104115# Crop the bitmap
1992 if( rAttr.IsCropped() )
1994 rBmpEx.Crop( rCropRect );
1996 // #104115# Negative crop sizes mean: enlarge bitmap and pad
1997 if( bEnlarge && (
1998 rCropLeftTop.Width() < 0 ||
1999 rCropLeftTop.Height() < 0 ||
2000 rCropRightBottom.Width() < 0 ||
2001 rCropRightBottom.Height() < 0 ) )
2003 Size aBmpSize( rBmpEx.GetSizePixel() );
2004 sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
2005 sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
2006 sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
2007 sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
2009 BitmapEx aBmpEx2;
2011 if( rBmpEx.IsTransparent() )
2013 if( rBmpEx.IsAlpha() )
2014 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
2015 else
2016 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
2018 else
2020 // #104115# Generate mask bitmap and init to zero
2021 Bitmap aMask( aBmpSize, 1 );
2022 aMask.Erase( Color(0,0,0) );
2024 // #104115# Always generate transparent bitmap, we need the border transparent
2025 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
2027 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2028 rBmpEx = aBmpEx2;
2031 aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
2032 aBmpEx2.Erase( Color(0xFF,0,0,0) );
2033 aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
2034 rBmpEx = aBmpEx2;
2038 const Size aSizePixel( rBmpEx.GetSizePixel() );
2040 if( rAttr.GetRotation() != 0 && !IsAnimated() )
2042 if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
2044 double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
2045 double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
2046 double fScaleX = 1.0, fScaleY = 1.0;
2048 // always choose scaling to shrink bitmap
2049 if( fSrcWH < fDstWH )
2050 fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
2051 else
2052 fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
2054 rBmpEx.Scale( fScaleX, fScaleY );
2059 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */