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