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