xref: /aoo41x/main/vcl/source/gdi/outdev2.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <tools/debug.hxx>
32 
33 #include <vcl/bitmap.hxx>
34 #include <vcl/bitmapex.hxx>
35 #include <vcl/window.hxx>
36 #include <vcl/metaact.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/bmpacc.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/window.hxx>
42 #include <vcl/image.hxx>
43 
44 #include <bmpfast.hxx>
45 #include <salbmp.hxx>
46 #include <salgdi.hxx>
47 #include <impbmp.hxx>
48 #include <sallayout.hxx>
49 #include <image.h>
50 #include <outdev.h>
51 #include <window.h>
52 #include <region.h>
53 #include <outdata.hxx>
54 
55 #define BAND_MAX_SIZE 512000
56 
57 // =======================================================================
58 
59 DBG_NAMEEX( OutputDevice )
60 
61 // =======================================================================
62 
63 // -----------
64 // - Defines -
65 // -----------
66 
67 #define OUTDEV_INIT()						\
68 {											\
69 	if ( !IsDeviceOutputNecessary() )		\
70 		return; 							\
71 											\
72 	if ( !mpGraphics )						\
73 		if ( !ImplGetGraphics() )			\
74 			return; 						\
75 											\
76 	if ( mbInitClipRegion ) 				\
77 		ImplInitClipRegion();				\
78 											\
79 	if ( mbOutputClipped )					\
80 		return; 							\
81 }
82 
83 #define TwoRect 	SalTwoRect
84 
85 // -------------
86 // - externals -
87 // -------------
88 
89 extern sal_uLong nVCLRLut[ 6 ];
90 extern sal_uLong nVCLGLut[ 6 ];
91 extern sal_uLong nVCLBLut[ 6 ];
92 extern sal_uLong nVCLDitherLut[ 256 ];
93 extern sal_uLong nVCLLut[ 256 ];
94 
95 // =======================================================================
96 
97 sal_uLong ImplAdjustTwoRect( TwoRect& rTwoRect, const Size& rSizePix )
98 {
99 	sal_uLong nMirrFlags = 0;
100 
101 	if ( rTwoRect.mnDestWidth < 0 )
102 	{
103 		rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
104 		rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
105 		rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
106 		nMirrFlags |= BMP_MIRROR_HORZ;
107 	}
108 
109 	if ( rTwoRect.mnDestHeight < 0 )
110 	{
111 		rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
112 		rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
113 		rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
114 		nMirrFlags |= BMP_MIRROR_VERT;
115 	}
116 
117 	if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
118 		( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
119 		( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
120 		( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
121 	{
122 		const Rectangle	aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
123 									 Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
124 		Rectangle		aCropRect( aSourceRect );
125 
126 		aCropRect.Intersection( Rectangle( Point(), rSizePix ) );
127 
128 		if( aCropRect.IsEmpty() )
129 			rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
130 		else
131 		{
132 			const double	fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
133 			const double	fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
134 
135 			const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
136 			const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
137 			const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
138 			const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
139 
140 			rTwoRect.mnSrcX = aCropRect.Left();
141 			rTwoRect.mnSrcY = aCropRect.Top();
142 			rTwoRect.mnSrcWidth = aCropRect.GetWidth();
143 			rTwoRect.mnSrcHeight = aCropRect.GetHeight();
144 			rTwoRect.mnDestX = nDstX1;
145 			rTwoRect.mnDestY = nDstY1;
146 			rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
147 			rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
148 		}
149 	}
150 
151 	return nMirrFlags;
152 }
153 
154 // =======================================================================
155 
156 void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pVoidPosAry )
157 {
158 	TwoRect*			pPosAry = (TwoRect*)pVoidPosAry;
159 	SalGraphics*		pGraphics2;
160 
161 	if ( pPosAry->mnSrcWidth && pPosAry->mnSrcHeight && pPosAry->mnDestWidth && pPosAry->mnDestHeight )
162 	{
163 		if ( this == pSrcDev )
164 			pGraphics2 = NULL;
165 		else
166 		{
167 			if ( (GetOutDevType() != pSrcDev->GetOutDevType()) ||
168 				 (GetOutDevType() != OUTDEV_WINDOW) )
169 			{
170 				if ( !pSrcDev->mpGraphics )
171 				{
172 					if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
173 						return;
174 				}
175 				pGraphics2 = pSrcDev->mpGraphics;
176 			}
177 			else
178 			{
179 				if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow )
180 					pGraphics2 = NULL;
181 				else
182 				{
183 					if ( !pSrcDev->mpGraphics )
184 					{
185 						if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
186 							return;
187 					}
188 					pGraphics2 = pSrcDev->mpGraphics;
189 
190 					if ( !mpGraphics )
191 					{
192 						if ( !ImplGetGraphics() )
193 							return;
194 					}
195 					DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics,
196 								"OutputDevice::DrawOutDev(): We need more than one Graphics" );
197 				}
198 			}
199 		}
200 
201         // #102532# Offset only has to be pseudo window offset
202 		Rectangle	aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ),
203 								 Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) );
204 		Rectangle	aSrcRect( Point( pPosAry->mnSrcX, pPosAry->mnSrcY ),
205 							  Size( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
206 		const long	nOldRight = aSrcRect.Right();
207 		const long	nOldBottom = aSrcRect.Bottom();
208 
209 		if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
210 		{
211 			if ( (pPosAry->mnSrcX+pPosAry->mnSrcWidth-1) > aSrcOutRect.Right() )
212 			{
213 				const long nOldWidth = pPosAry->mnSrcWidth;
214 				pPosAry->mnSrcWidth -= (nOldRight - aSrcRect.Right());
215 				pPosAry->mnDestWidth = pPosAry->mnDestWidth * pPosAry->mnSrcWidth / nOldWidth;
216 			}
217 
218 			if ( (pPosAry->mnSrcY+pPosAry->mnSrcHeight-1) > aSrcOutRect.Bottom() )
219 			{
220 				const long nOldHeight = pPosAry->mnSrcHeight;
221 				pPosAry->mnSrcHeight -= (nOldBottom - aSrcRect.Bottom());
222 				pPosAry->mnDestHeight = pPosAry->mnDestHeight * pPosAry->mnSrcHeight / nOldHeight;
223 			}
224 
225             // --- RTL --- if this is no window, but pSrcDev is a window
226             // mirroring may be required
227             // because only windows have a SalGraphicsLayout
228             // mirroring is performed here
229             if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) )
230             {
231 		        SalTwoRect pPosAry2 = *pPosAry;
232 			    pGraphics2->mirror( pPosAry2.mnSrcX, pPosAry2.mnSrcWidth, pSrcDev );
233 			    mpGraphics->CopyBits( &pPosAry2, pGraphics2, this, pSrcDev );
234             }
235             else
236 			    mpGraphics->CopyBits( pPosAry, pGraphics2, this, pSrcDev );
237 		}
238 	}
239 }
240 
241 // ------------------------------------------------------------------
242 
243 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
244 							   const Point& rSrcPt,  const Size& rSrcSize )
245 {
246 	DBG_TRACE( "OutputDevice::DrawOutDev()" );
247 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
248 	DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
249 
250     if( ImplIsRecordLayout() )
251         return;
252 
253 	if ( meOutDevType == OUTDEV_PRINTER )
254 		return;
255 
256 	if ( ROP_INVERT == meRasterOp )
257 	{
258 		DrawRect( Rectangle( rDestPt, rDestSize ) );
259 		return;
260 	}
261 
262 	if ( mpMetaFile )
263 	{
264 		const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) );
265 		mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
266 	}
267 
268 	OUTDEV_INIT();
269 
270 	TwoRect aPosAry;
271 	aPosAry.mnSrcWidth	 = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
272 	aPosAry.mnSrcHeight  = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
273 	aPosAry.mnDestWidth  = ImplLogicWidthToDevicePixel( rDestSize.Width() );
274 	aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
275 
276 	if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
277 	{
278 		aPosAry.mnSrcX		 = ImplLogicXToDevicePixel( rSrcPt.X() );
279 		aPosAry.mnSrcY		 = ImplLogicYToDevicePixel( rSrcPt.Y() );
280 		aPosAry.mnDestX 	 = ImplLogicXToDevicePixel( rDestPt.X() );
281 		aPosAry.mnDestY 	 = ImplLogicYToDevicePixel( rDestPt.Y() );
282 
283 		Rectangle	aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
284 								 Size( mnOutWidth, mnOutHeight ) );
285 		Rectangle	aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
286 							  Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
287 		long		nOldRight = aSrcRect.Right();
288 		long		nOldBottom = aSrcRect.Bottom();
289 
290 		if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
291 		{
292 			if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
293 			{
294 				long nOldWidth = aPosAry.mnSrcWidth;
295 				aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
296 				aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth;
297 			}
298 
299 			if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
300 			{
301 				long nOldHeight = aPosAry.mnSrcHeight;
302 				aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
303 				aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight;
304 			}
305 
306 			mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
307 		}
308 	}
309 
310     if( mpAlphaVDev )
311         mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize );
312 }
313 
314 // ------------------------------------------------------------------
315 
316 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
317 							   const Point& rSrcPt,  const Size& rSrcSize,
318 							   const OutputDevice& rOutDev )
319 {
320 	DBG_TRACE( "OutputDevice::DrawOutDev()" );
321 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
322 	DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice );
323 	DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
324 	DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
325 
326 	if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) || ImplIsRecordLayout() )
327 		return;
328 
329 	if ( ROP_INVERT == meRasterOp )
330 	{
331 		DrawRect( Rectangle( rDestPt, rDestSize ) );
332 		return;
333 	}
334 
335 	if ( mpMetaFile )
336 	{
337 		const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) );
338 		mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
339 	}
340 
341 	OUTDEV_INIT();
342 
343 	TwoRect aPosAry;
344 	aPosAry.mnSrcX		 = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() );
345 	aPosAry.mnSrcY		 = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() );
346 	aPosAry.mnSrcWidth	 = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() );
347 	aPosAry.mnSrcHeight  = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() );
348 	aPosAry.mnDestX 	 = ImplLogicXToDevicePixel( rDestPt.X() );
349 	aPosAry.mnDestY 	 = ImplLogicYToDevicePixel( rDestPt.Y() );
350 	aPosAry.mnDestWidth  = ImplLogicWidthToDevicePixel( rDestSize.Width() );
351 	aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
352 
353     if( mpAlphaVDev )
354     {
355         if( rOutDev.mpAlphaVDev )
356         {
357             // alpha-blend source over destination
358             DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
359 
360             // This would be mode SOURCE:
361             // copy source alpha channel to our alpha channel
362             //mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize, *rOutDev.mpAlphaVDev );
363         }
364         else
365         {
366             ImplDrawOutDevDirect( &rOutDev, &aPosAry );
367 
368             // #i32109#: make destination rectangle opaque - source has no alpha
369             mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
370         }
371     }
372     else
373     {
374         if( rOutDev.mpAlphaVDev )
375         {
376             // alpha-blend source over destination
377             DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
378         }
379         else
380         {
381             // no alpha at all, neither in source nor destination device
382             ImplDrawOutDevDirect( &rOutDev, &aPosAry );
383         }
384     }
385 }
386 
387 // ------------------------------------------------------------------
388 
389 void OutputDevice::CopyArea( const Point& rDestPt,
390 							 const Point& rSrcPt,  const Size& rSrcSize,
391 							 sal_uInt16 nFlags )
392 {
393 	DBG_TRACE( "OutputDevice::CopyArea()" );
394 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
395 	DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" );
396 
397 	if ( meOutDevType == OUTDEV_PRINTER || ImplIsRecordLayout() )
398 		return;
399 
400 	RasterOp eOldRop = GetRasterOp();
401 	SetRasterOp( ROP_OVERPAINT );
402 
403 	OUTDEV_INIT();
404 
405 	TwoRect aPosAry;
406 	aPosAry.mnSrcWidth	 = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
407 	aPosAry.mnSrcHeight  = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
408 
409 	if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight )
410 	{
411 		aPosAry.mnSrcX		 = ImplLogicXToDevicePixel( rSrcPt.X() );
412 		aPosAry.mnSrcY		 = ImplLogicYToDevicePixel( rSrcPt.Y() );
413 		aPosAry.mnDestX 	 = ImplLogicXToDevicePixel( rDestPt.X() );
414 		aPosAry.mnDestY 	 = ImplLogicYToDevicePixel( rDestPt.Y() );
415 
416 		Rectangle	aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
417 								 Size( mnOutWidth, mnOutHeight ) );
418 		Rectangle	aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
419 							  Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
420 		long		nOldRight = aSrcRect.Right();
421 		long		nOldBottom = aSrcRect.Bottom();
422 
423 		if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
424 		{
425 			if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
426 				aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
427 
428 			if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
429 				aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
430 
431 			if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) )
432 			{
433 				((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect,
434 															   aPosAry.mnDestX-aPosAry.mnSrcX,
435 															   aPosAry.mnDestY-aPosAry.mnSrcY,
436 															   sal_False );
437 
438 				mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY,
439 									  aPosAry.mnSrcX, aPosAry.mnSrcY,
440 									  aPosAry.mnSrcWidth, aPosAry.mnSrcHeight,
441 									  SAL_COPYAREA_WINDOWINVALIDATE, this );
442 			}
443 			else
444 			{
445 				aPosAry.mnDestWidth  = aPosAry.mnSrcWidth;
446 				aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
447 				mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
448 			}
449 		}
450 	}
451 
452 	SetRasterOp( eOldRop );
453 
454     if( mpAlphaVDev )
455         mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags );
456 }
457 
458 // ------------------------------------------------------------------
459 
460 void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
461 									 const OutputDevice& rOutDev, const Region& rRegion )
462 {
463 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
464 
465 	GDIMetaFile*	pOldMetaFile = mpMetaFile;
466 	sal_Bool			bOldMap = mbMap;
467 	RasterOp		eOldROP = GetRasterOp();
468 	mpMetaFile = NULL;
469 	mbMap = sal_False;
470 	SetRasterOp( ROP_OVERPAINT );
471 
472 	if ( !IsDeviceOutputNecessary() )
473 		return;
474 
475 	if ( !mpGraphics )
476 	{
477 		if ( !ImplGetGraphics() )
478 			return;
479 	}
480 
481 	// ClipRegion zuruecksetzen
482 	if ( rRegion.IsNull() )
483 		mpGraphics->ResetClipRegion();
484 	else
485 		ImplSelectClipRegion( rRegion );
486 
487 	TwoRect aPosAry;
488 	aPosAry.mnSrcX		 = rDevPt.X();
489 	aPosAry.mnSrcY		 = rDevPt.Y();
490 	aPosAry.mnSrcWidth	 = rDevSize.Width();
491 	aPosAry.mnSrcHeight  = rDevSize.Height();
492 	aPosAry.mnDestX 	 = rPt.X();
493 	aPosAry.mnDestY 	 = rPt.Y();
494 	aPosAry.mnDestWidth  = rDevSize.Width();
495 	aPosAry.mnDestHeight = rDevSize.Height();
496 	ImplDrawOutDevDirect( &rOutDev, &aPosAry );
497 
498 	// Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird
499 	mbInitClipRegion = sal_True;
500 
501 	SetRasterOp( eOldROP );
502 	mbMap = bOldMap;
503 	mpMetaFile = pOldMetaFile;
504 }
505 
506 // ------------------------------------------------------------------
507 
508 void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
509 									OutputDevice& rDev )
510 {
511 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
512 
513 	sal_Bool bOldMap = mbMap;
514 	mbMap = sal_False;
515 	rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this );
516 	mbMap = bOldMap;
517 }
518 
519 // ------------------------------------------------------------------
520 
521 void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
522 {
523 	DBG_TRACE( "OutputDevice::DrawBitmap()" );
524 
525     if( ImplIsRecordLayout() )
526         return;
527 
528 	const Size aSizePix( rBitmap.GetSizePixel() );
529 	ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
530 
531     if( mpAlphaVDev )
532     {
533         // #i32109#: Make bitmap area opaque
534         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) );
535     }
536 }
537 
538 // ------------------------------------------------------------------
539 
540 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
541 {
542 	DBG_TRACE( "OutputDevice::DrawBitmap( Size )" );
543 
544     if( ImplIsRecordLayout() )
545         return;
546 
547 	ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
548 
549     if( mpAlphaVDev )
550     {
551         // #i32109#: Make bitmap area opaque
552         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
553     }
554 }
555 
556 // ------------------------------------------------------------------
557 
558 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
559 							   const Point& rSrcPtPixel, const Size& rSrcSizePixel,
560 							   const Bitmap& rBitmap )
561 {
562 	DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" );
563 
564     if( ImplIsRecordLayout() )
565         return;
566 
567 	ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION );
568 
569     if( mpAlphaVDev )
570     {
571         // #i32109#: Make bitmap area opaque
572         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
573     }
574 }
575 
576 // -----------------------------------------------------------------------------
577 
578 void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
579 								   const Point& rSrcPtPixel, const Size& rSrcSizePixel,
580 								   const Bitmap& rBitmap, const sal_uLong nAction )
581 {
582 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
583 
584 	Bitmap aBmp( rBitmap );
585 
586 	if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
587 		return;
588 	else if ( ROP_INVERT == meRasterOp )
589 	{
590 		DrawRect( Rectangle( rDestPt, rDestSize ) );
591 		return;
592 	}
593 	else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
594 							 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
595 	{
596 		if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
597 		{
598 			sal_uInt8 cCmpVal;
599 
600 			if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
601 				cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
602 			else
603 				cCmpVal = 255;
604 
605 			Color aCol( cCmpVal, cCmpVal, cCmpVal );
606 			Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
607 			SetLineColor( aCol );
608 			SetFillColor( aCol );
609 			DrawRect( Rectangle( rDestPt, rDestSize ) );
610 			Pop();
611 			return;
612 		}
613 		else if( !!aBmp )
614 		{
615 			if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
616 				aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
617 
618 			if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
619 				aBmp.Convert( BMP_CONVERSION_GHOSTED );
620 		}
621 	}
622 
623 	if ( mpMetaFile )
624 	{
625 		switch( nAction )
626 		{
627 			case( META_BMP_ACTION ):
628 				mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
629 			break;
630 
631 			case( META_BMPSCALE_ACTION ):
632 				mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
633 			break;
634 
635 			case( META_BMPSCALEPART_ACTION ):
636 				mpMetaFile->AddAction( new MetaBmpScalePartAction(
637 					rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
638 			break;
639 		}
640 	}
641 
642 	OUTDEV_INIT();
643 
644 	if( !aBmp.IsEmpty() )
645 	{
646 		TwoRect aPosAry;
647 
648 		aPosAry.mnSrcX = rSrcPtPixel.X();
649 		aPosAry.mnSrcY = rSrcPtPixel.Y();
650 		aPosAry.mnSrcWidth = rSrcSizePixel.Width();
651 		aPosAry.mnSrcHeight = rSrcSizePixel.Height();
652 		aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
653 		aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
654 		aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
655 		aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
656 
657 		const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
658 
659 		if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
660 		{
661 			if ( nMirrFlags )
662 				aBmp.Mirror( nMirrFlags );
663 
664             /* #i75264# (corrected with #i81576#)
665             * sometimes a bitmap is scaled to a ridiculous size and drawn
666             * to a quite normal VDev, so only a very small part of
667             * the scaled bitmap will be visible. However actually scaling
668             * the bitmap will use so much memory that we end with a crash.
669             * Workaround: since only a small part of the scaled bitmap will
670             * be actually drawn anyway (because of clipping on the device
671             * boundary), limit the destination and source rectangles so
672             * that the destination rectangle will overlap the device but only
673             * be reasonably (say factor 2) larger than the device itself.
674             */
675             if( aPosAry.mnDestWidth > 2048 || aPosAry.mnDestHeight > 2048 )
676             {
677                  if( meOutDevType == OUTDEV_WINDOW ||
678                      (meOutDevType == OUTDEV_VIRDEV && mpPDFWriter == 0 ) )
679                 {
680                     // #i81576# do the following trick only if there is overlap at all
681                     // else the formulae don't work
682                     // theoretically in this case we wouldn't need to draw the bitmap at all
683                     // however there are some esoteric case where that is needed
684                     if( aPosAry.mnDestX + aPosAry.mnDestWidth >= 0
685                         && aPosAry.mnDestX < mnOutWidth
686                         && aPosAry.mnDestY + aPosAry.mnDestHeight >= 0
687                         && aPosAry.mnDestY < mnOutHeight )
688                     {
689                         // reduce scaling to something reasonable taking into account the output size
690                         if( aPosAry.mnDestWidth > 3*mnOutWidth && aPosAry.mnSrcWidth )
691                         {
692                             const double nScaleX = aPosAry.mnDestWidth/double(aPosAry.mnSrcWidth);
693 
694                             if( aPosAry.mnDestX + aPosAry.mnDestWidth > mnOutWidth )
695                             {
696                                 aPosAry.mnDestWidth = Max(long(0),mnOutWidth-aPosAry.mnDestX);
697                             }
698                             if( aPosAry.mnDestX < 0 )
699                             {
700                                 aPosAry.mnDestWidth += aPosAry.mnDestX;
701                                 aPosAry.mnSrcX -= sal::static_int_cast<long>(aPosAry.mnDestX / nScaleX);
702                                 aPosAry.mnDestX = 0;
703                             }
704 
705                             aPosAry.mnSrcWidth = sal::static_int_cast<long>(aPosAry.mnDestWidth / nScaleX);
706                         }
707 
708                         if( aPosAry.mnDestHeight > 3*mnOutHeight && aPosAry.mnSrcHeight != 0 )
709                         {
710                             const double nScaleY = aPosAry.mnDestHeight/double(aPosAry.mnSrcHeight);
711 
712                             if( aPosAry.mnDestY + aPosAry.mnDestHeight > mnOutHeight )
713                             {
714                                 aPosAry.mnDestHeight = Max(long(0),mnOutHeight-aPosAry.mnDestY);
715                             }
716                             if( aPosAry.mnDestY < 0 )
717                             {
718                                 aPosAry.mnDestHeight += aPosAry.mnDestY;
719                                 aPosAry.mnSrcY -= sal::static_int_cast<long>(aPosAry.mnDestY / nScaleY);
720                                 aPosAry.mnDestY = 0;
721                             }
722 
723                             aPosAry.mnSrcHeight = sal::static_int_cast<long>(aPosAry.mnDestHeight / nScaleY);
724                         }
725                     }
726                 }
727             }
728 
729             if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
730                 mpGraphics->DrawBitmap( &aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
731 		}
732 	}
733 }
734 
735 // ------------------------------------------------------------------
736 
737 void OutputDevice::DrawBitmapEx( const Point& rDestPt,
738 								 const BitmapEx& rBitmapEx )
739 {
740 	DBG_TRACE( "OutputDevice::DrawBitmapEx()" );
741 
742     if( ImplIsRecordLayout() )
743         return;
744 
745 	if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
746 		DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
747 	else
748 	{
749 		const Size aSizePix( rBitmapEx.GetSizePixel() );
750 		ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
751 	}
752 }
753 
754 // ------------------------------------------------------------------
755 
756 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
757 								 const BitmapEx& rBitmapEx )
758 {
759 	DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" );
760 
761     if( ImplIsRecordLayout() )
762         return;
763 
764 	if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
765 		DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
766 	else
767 		ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
768 }
769 
770 // ------------------------------------------------------------------
771 
772 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
773 								 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
774 								 const BitmapEx& rBitmapEx )
775 {
776 	DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" );
777 
778     if( ImplIsRecordLayout() )
779         return;
780 
781 	if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
782 		DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
783 	else
784 		ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION );
785 }
786 
787 // ------------------------------------------------------------------
788 
789 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
790 									 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
791 									 const BitmapEx& rBitmapEx, const sal_uLong nAction )
792 {
793 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
794 
795 	BitmapEx aBmpEx( rBitmapEx );
796 
797 	if ( mnDrawMode & DRAWMODE_NOBITMAP )
798 		return;
799 	else if ( ROP_INVERT == meRasterOp )
800 	{
801 		DrawRect( Rectangle( rDestPt, rDestSize ) );
802 		return;
803 	}
804 	else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
805 							 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
806 	{
807 		if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
808 		{
809 			Bitmap	aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
810 			sal_uInt8	cCmpVal;
811 
812 			if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
813 				cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
814 			else
815 				cCmpVal = 255;
816 
817 			aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
818 
819 			if( aBmpEx.IsAlpha() )
820             {
821                 // Create one-bit mask out of alpha channel, by
822                 // thresholding it at alpha=0.5. As
823                 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
824                 // output, having alpha-induced grey levels is not
825                 // acceptable.
826                 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
827                 aMask.MakeMono( 128 );
828 				aBmpEx = BitmapEx( aColorBmp, aMask );
829             }
830 			else
831             {
832 				aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
833             }
834 		}
835 		else if( !!aBmpEx )
836 		{
837 			if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
838 				aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
839 
840 			if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
841 				aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
842 		}
843 	}
844 
845 	if ( mpMetaFile )
846 	{
847 		switch( nAction )
848 		{
849 			case( META_BMPEX_ACTION ):
850 				mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
851 			break;
852 
853 			case( META_BMPEXSCALE_ACTION ):
854 				mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
855 			break;
856 
857 			case( META_BMPEXSCALEPART_ACTION ):
858 				mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
859 																	 rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
860 			break;
861 		}
862 	}
863 
864 	OUTDEV_INIT();
865 
866 	if( OUTDEV_PRINTER == meOutDevType )
867 	{
868         if( aBmpEx.IsAlpha() )
869         {
870             // #107169# For true alpha bitmaps, no longer masking the
871             // bitmap, but perform a full alpha blend against a white
872             // background here.
873             Bitmap aBmp( aBmpEx.GetBitmap() );
874             aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) );
875             DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
876         }
877         else
878         {
879             Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() );
880             aBmp.Replace( aMask, Color( COL_WHITE ) );
881             ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
882         }
883 	    return;
884 	}
885 	else if( aBmpEx.IsAlpha() )
886 	{
887 		ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
888 		return;
889 	}
890 
891 	if( !( !aBmpEx ) )
892 	{
893 		TwoRect aPosAry;
894 
895 		aPosAry.mnSrcX = rSrcPtPixel.X();
896 		aPosAry.mnSrcY = rSrcPtPixel.Y();
897 		aPosAry.mnSrcWidth = rSrcSizePixel.Width();
898 		aPosAry.mnSrcHeight = rSrcSizePixel.Height();
899 		aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
900 		aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
901 		aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
902 		aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
903 
904 		const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() );
905 
906 		if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
907 		{
908 
909 			if( nMirrFlags )
910 				aBmpEx.Mirror( nMirrFlags );
911 
912 			const ImpBitmap* pImpBmp = aBmpEx.ImplGetBitmapImpBitmap();
913 			const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap();
914 
915 			if ( pMaskBmp )
916             {
917                 // #4919452# reduce operation area to bounds of
918                 // cliprect. since masked transparency involves
919                 // creation of a large vdev and copying the screen
920                 // content into that (slooow read from framebuffer),
921                 // that should considerably increase performance for
922                 // large bitmaps and small clippings.
923 
924                 // Note that this optimisation is a workaround for a
925                 // Writer peculiarity, namely, to decompose background
926                 // graphics into myriads of disjunct, tiny
927                 // rectangles. That otherwise kills us here, since for
928                 // transparent output, SAL always prepares the whole
929                 // bitmap, if aPosAry contains the whole bitmap (and
930                 // it's _not_ to blame for that).
931 
932                 // Note the call to ImplPixelToDevicePixel(), since
933                 // aPosAry already contains the mnOutOff-offsets, they
934                 // also have to be applied to the region
935                 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
936 
937                 // TODO: Also respect scaling (that's a bit tricky,
938                 // since the source points have to move fractional
939                 // amounts (which is not possible, thus has to be
940                 // emulated by increases copy area)
941                 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
942                 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
943 
944                 // for now, only identity scales allowed
945                 if( !aClipRegionBounds.IsEmpty() &&
946                     aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
947                     aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
948                 {
949                     // now intersect dest rect with clip region
950                     aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
951                                                                aPosAry.mnDestY,
952                                                                aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
953                                                                aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
954 
955                     // Note: I could theoretically optimize away the
956                     // DrawBitmap below, if the region is empty
957                     // here. Unfortunately, cannot rule out that
958                     // somebody relies on the side effects.
959                     if( !aClipRegionBounds.IsEmpty() )
960                     {
961                         aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
962                         aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
963                         aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
964                         aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
965 
966                         aPosAry.mnDestX = aClipRegionBounds.Left();
967                         aPosAry.mnDestY = aClipRegionBounds.Top();
968                         aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
969                         aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
970                     }
971                 }
972 
973 				mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
974                                         *pMaskBmp->ImplGetSalBitmap(),
975                                         this );
976 
977                 // #110958# Paint mask to alpha channel. Luckily, the
978                 // black and white representation of the mask maps to
979                 // the alpha channel
980 
981                 // #i25167# Restrict mask painting to _opaque_ areas
982                 // of the mask, otherwise we spoil areas where no
983                 // bitmap content was ever visible. Interestingly
984                 // enough, this can be achieved by taking the mask as
985                 // the transparency mask of itself
986                 if( mpAlphaVDev )
987                     mpAlphaVDev->DrawBitmapEx( rDestPt,
988                                                rDestSize,
989                                                BitmapEx( aBmpEx.GetMask(),
990                                                          aBmpEx.GetMask() ) );
991             }
992 			else
993             {
994 				mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(), this );
995 
996                 if( mpAlphaVDev )
997                 {
998                     // #i32109#: Make bitmap area opaque
999                     mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
1000                 }
1001             }
1002 		}
1003 	}
1004 }
1005 
1006 // ------------------------------------------------------------------
1007 
1008 void OutputDevice::DrawMask( const Point& rDestPt,
1009 							 const Bitmap& rBitmap, const Color& rMaskColor )
1010 {
1011 	DBG_TRACE( "OutputDevice::DrawMask()" );
1012 
1013     if( ImplIsRecordLayout() )
1014         return;
1015 
1016 	const Size aSizePix( rBitmap.GetSizePixel() );
1017 	ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
1018 
1019     if( mpAlphaVDev )
1020     {
1021         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1022 
1023         // #i25167# Restrict mask painting to _opaque_ areas
1024         // of the mask, otherwise we spoil areas where no
1025         // bitmap content was ever visible. Interestingly
1026         // enough, this can be achieved by taking the mask as
1027         // the transparency mask of itself
1028         mpAlphaVDev->DrawBitmapEx( rDestPt,
1029                                    PixelToLogic( aSizePix ),
1030                                    BitmapEx( rMask, rMask ) );
1031     }
1032 }
1033 
1034 // ------------------------------------------------------------------
1035 
1036 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1037 							 const Bitmap& rBitmap, const Color& rMaskColor )
1038 {
1039 	DBG_TRACE( "OutputDevice::DrawMask( Size )" );
1040 
1041     if( ImplIsRecordLayout() )
1042         return;
1043 
1044 	ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
1045 
1046     // TODO: Use mask here
1047     if( mpAlphaVDev )
1048     {
1049         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1050 
1051         // #i25167# Restrict mask painting to _opaque_ areas
1052         // of the mask, otherwise we spoil areas where no
1053         // bitmap content was ever visible. Interestingly
1054         // enough, this can be achieved by taking the mask as
1055         // the transparency mask of itself
1056         mpAlphaVDev->DrawBitmapEx( rDestPt,
1057                                    rDestSize,
1058                                    BitmapEx( rMask, rMask ) );
1059     }
1060 }
1061 
1062 // ------------------------------------------------------------------
1063 
1064 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1065 							 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1066 							 const Bitmap& rBitmap, const Color& rMaskColor )
1067 {
1068 	DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" );
1069 
1070     if( ImplIsRecordLayout() )
1071         return;
1072 
1073 	ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION );
1074 
1075     // TODO: Use mask here
1076     if( mpAlphaVDev )
1077     {
1078         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1079 
1080         // #i25167# Restrict mask painting to _opaque_ areas
1081         // of the mask, otherwise we spoil areas where no
1082         // bitmap content was ever visible. Interestingly
1083         // enough, this can be achieved by taking the mask as
1084         // the transparency mask of itself
1085         mpAlphaVDev->DrawBitmapEx( rDestPt,
1086                                    rDestSize,
1087                                    rSrcPtPixel,
1088                                    rSrcSizePixel,
1089                                    BitmapEx( rMask, rMask ) );
1090     }
1091 }
1092 
1093 // ------------------------------------------------------------------
1094 
1095 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
1096 								 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1097 								 const Bitmap& rBitmap, const Color& rMaskColor,
1098 								 const sal_uLong nAction )
1099 {
1100 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1101 
1102 	if( ROP_INVERT == meRasterOp )
1103 	{
1104 		DrawRect( Rectangle( rDestPt, rDestSize ) );
1105 		return;
1106 	}
1107 
1108 	if ( mpMetaFile )
1109 	{
1110 		switch( nAction )
1111 		{
1112 			case( META_MASK_ACTION ):
1113 				mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
1114 					rBitmap, rMaskColor ) );
1115 			break;
1116 
1117 			case( META_MASKSCALE_ACTION ):
1118 				mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
1119 					rDestSize, rBitmap, rMaskColor ) );
1120 			break;
1121 
1122 			case( META_MASKSCALEPART_ACTION ):
1123 				mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
1124 					rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
1125 			break;
1126 		}
1127 	}
1128 
1129 	OUTDEV_INIT();
1130 
1131 	if ( OUTDEV_PRINTER == meOutDevType )
1132 	{
1133 		ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1134 		return;
1135 	}
1136 
1137 	const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
1138 	if ( pImpBmp )
1139 	{
1140 		TwoRect aPosAry;
1141 
1142 		aPosAry.mnSrcX = rSrcPtPixel.X();
1143 		aPosAry.mnSrcY = rSrcPtPixel.Y();
1144 		aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1145 		aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1146 		aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1147 		aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1148 		aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1149 		aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1150 
1151 		// spiegeln via Koordinaten wollen wir nicht
1152 		const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
1153 
1154 		// check if output is necessary
1155 		if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1156 		{
1157 
1158 			if( nMirrFlags )
1159 			{
1160 				Bitmap aTmp( rBitmap );
1161 				aTmp.Mirror( nMirrFlags );
1162 				mpGraphics->DrawMask( &aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
1163 									  ImplColorToSal( rMaskColor ) , this);
1164 			}
1165 			else
1166 				mpGraphics->DrawMask( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
1167 									  ImplColorToSal( rMaskColor ), this );
1168 
1169 		}
1170 	}
1171 }
1172 
1173 // ------------------------------------------------------------------
1174 
1175 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle )
1176 {
1177 	DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1178 
1179 	if( !rImage.mpImplData || ImplIsRecordLayout() )
1180 		return;
1181 
1182 	switch( rImage.mpImplData->meType )
1183 	{
1184 		case IMAGETYPE_BITMAP:
1185 			DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1186 		break;
1187 
1188 		case IMAGETYPE_IMAGE:
1189 		{
1190 			ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1191 
1192 			if( !pData->mpImageBitmap )
1193 			{
1194 				const Size aSize( pData->maBmpEx.GetSizePixel() );
1195 
1196 				pData->mpImageBitmap = new ImplImageBmp;
1197 				pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1198 			}
1199 
1200 			pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1201 		}
1202 		break;
1203 
1204 		default:
1205 		break;
1206 	}
1207 }
1208 
1209 // ------------------------------------------------------------------
1210 
1211 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1212 							  const Image& rImage, sal_uInt16 nStyle )
1213 {
1214 	DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1215 
1216 	if( rImage.mpImplData && !ImplIsRecordLayout() )
1217 	{
1218 		switch( rImage.mpImplData->meType )
1219 		{
1220 			case IMAGETYPE_BITMAP:
1221 				DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1222 			break;
1223 
1224 			case IMAGETYPE_IMAGE:
1225 			{
1226 				ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1227 
1228 				if ( !pData->mpImageBitmap )
1229 				{
1230 					const Size aSize( pData->maBmpEx.GetSizePixel() );
1231 
1232 					pData->mpImageBitmap = new ImplImageBmp;
1233 					pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1234 				}
1235 
1236 				pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1237 			}
1238 			break;
1239 
1240 			default:
1241 			break;
1242 		}
1243 	}
1244 }
1245 
1246 // ------------------------------------------------------------------
1247 
1248 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1249 {
1250 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1251 
1252 	Bitmap	aBmp;
1253 	long	nX = ImplLogicXToDevicePixel( rSrcPt.X() );
1254 	long	nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
1255 	long	nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
1256 	long	nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
1257 
1258 	if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
1259 	{
1260 		if ( nWidth && nHeight )
1261 		{
1262 			Rectangle	aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
1263 			sal_Bool		bClipped = sal_False;
1264 
1265 			// X-Koordinate ausserhalb des Bereichs?
1266 			if ( nX < mnOutOffX )
1267 			{
1268 				nWidth -= ( mnOutOffX - nX );
1269 				nX = mnOutOffX;
1270 				bClipped = sal_True;
1271 			}
1272 
1273 			// Y-Koordinate ausserhalb des Bereichs?
1274 			if ( nY < mnOutOffY )
1275 			{
1276 				nHeight -= ( mnOutOffY - nY );
1277 				nY = mnOutOffY;
1278 				bClipped = sal_True;
1279 			}
1280 
1281 			// Breite ausserhalb des Bereichs?
1282 			if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
1283 			{
1284 				nWidth	= mnOutOffX + mnOutWidth - nX;
1285 				bClipped = sal_True;
1286 			}
1287 
1288 			// Hoehe ausserhalb des Bereichs?
1289 			if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
1290 			{
1291 				nHeight = mnOutOffY + mnOutHeight - nY;
1292 				bClipped = sal_True;
1293 			}
1294 
1295 			if ( bClipped )
1296 			{
1297 				// Falls auf den sichtbaren Bereich geclipped wurde,
1298 				// muessen wir eine Bitmap in der rchtigen Groesse
1299 				// erzeugen, in die die geclippte Bitmap an die angepasste
1300 				// Position kopiert wird
1301 				VirtualDevice aVDev( *this );
1302 
1303 				if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
1304 				{
1305 					if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
1306 					{
1307 						TwoRect aPosAry;
1308 
1309 						aPosAry.mnSrcX = nX;
1310 						aPosAry.mnSrcY = nY;
1311 						aPosAry.mnSrcWidth = nWidth;
1312 						aPosAry.mnSrcHeight = nHeight;
1313 						aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
1314 						aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
1315 						aPosAry.mnDestWidth = nWidth;
1316 						aPosAry.mnDestHeight = nHeight;
1317 
1318 						if ( (nWidth > 0) && (nHeight > 0) )
1319 							(((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( &aPosAry, mpGraphics, this, this );
1320 
1321 						aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
1322 					 }
1323 					 else
1324 						bClipped = sal_False;
1325 				}
1326 				else
1327 					bClipped = sal_False;
1328 			}
1329 
1330 			if ( !bClipped )
1331 			{
1332 				SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
1333 
1334 				if( pSalBmp )
1335 				{
1336 					ImpBitmap* pImpBmp = new ImpBitmap;
1337 					pImpBmp->ImplSetSalBitmap( pSalBmp );
1338 					aBmp.ImplSetImpBitmap( pImpBmp );
1339 				}
1340 			}
1341 		}
1342 	}
1343 
1344 	return aBmp;
1345 }
1346 
1347 // ------------------------------------------------------------------
1348 
1349 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
1350 {
1351 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1352 
1353     // #110958# Extract alpha value from VDev, if any
1354     if( mpAlphaVDev )
1355     {
1356         Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
1357 
1358         // ensure 8 bit alpha
1359         if( aAlphaBitmap.GetBitCount() > 8 )
1360             aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
1361 
1362         return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
1363     }
1364     else
1365         return GetBitmap( rSrcPt, rSize );
1366 }
1367 
1368 // ------------------------------------------------------------------
1369 
1370 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize,
1371 									   Bitmap& rBitmap ) const
1372 {
1373 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1374 
1375 	sal_Bool bOldMap = mbMap;
1376 	((OutputDevice*)this)->mbMap = sal_False;
1377 	rBitmap = GetBitmap( rDestPt, rSize );
1378 	((OutputDevice*)this)->mbMap = bOldMap;
1379 }
1380 
1381 // ------------------------------------------------------------------
1382 
1383 Color OutputDevice::GetPixel( const Point& rPt ) const
1384 {
1385 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1386 
1387 	Color aColor;
1388 
1389 	if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1390 	{
1391 		if ( mbInitClipRegion )
1392 			((OutputDevice*)this)->ImplInitClipRegion();
1393 
1394 		if ( !mbOutputClipped )
1395 		{
1396 			const long		nX = ImplLogicXToDevicePixel( rPt.X() );
1397 			const long		nY = ImplLogicYToDevicePixel( rPt.Y() );
1398 			const SalColor	aSalCol = mpGraphics->GetPixel( nX, nY, this );
1399 			aColor.SetRed( SALCOLOR_RED( aSalCol ) );
1400 			aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1401 			aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1402 		}
1403 	}
1404 	return aColor;
1405 }
1406 
1407 // ------------------------------------------------------------------
1408 
1409 Color* OutputDevice::GetPixel( const Polygon& rPts ) const
1410 {
1411 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1412 
1413 	Color*			pColors = NULL;
1414 	const sal_uInt16	nSize = rPts.GetSize();
1415 
1416 	if( nSize )
1417 	{
1418 		if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1419 		{
1420 			if ( mbInitClipRegion )
1421 				((OutputDevice*)this)->ImplInitClipRegion();
1422 
1423 			if ( !mbOutputClipped )
1424 			{
1425 				pColors = new Color[ nSize ];
1426 
1427 				for( sal_uInt16 i = 0; i < nSize; i++ )
1428 				{
1429 					Color&			rCol = pColors[ i ];
1430 					const Point&	rPt = rPts[ i ];
1431 					const SalColor	aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ),
1432 																   ImplLogicYToDevicePixel( rPt.Y() ) , this) );
1433 
1434 					rCol.SetRed( SALCOLOR_RED( aSalCol ) );
1435 					rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1436 					rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1437 				}
1438 			}
1439 		}
1440 	}
1441 
1442 	return pColors;
1443 }
1444 
1445 // -----------------------------------------------------------------------
1446 
1447 void OutputDevice::DrawPixel( const Point& rPt )
1448 {
1449 	DBG_TRACE( "OutputDevice::DrawPixel()" );
1450 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1451 
1452 	if ( mpMetaFile )
1453 		mpMetaFile->AddAction( new MetaPointAction( rPt ) );
1454 
1455 	if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
1456 		return;
1457 
1458 	Point aPt = ImplLogicToDevicePixel( rPt );
1459 
1460 	// we need a graphics
1461 	if ( !mpGraphics )
1462 	{
1463 		if ( !ImplGetGraphics() )
1464 			return;
1465 	}
1466 
1467 	if ( mbInitClipRegion )
1468 		ImplInitClipRegion();
1469 	if ( mbOutputClipped )
1470 		return;
1471 
1472 	if ( mbInitLineColor )
1473 		ImplInitLineColor();
1474 
1475 	mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
1476 
1477     if( mpAlphaVDev )
1478         mpAlphaVDev->DrawPixel( rPt );
1479 }
1480 
1481 // -----------------------------------------------------------------------
1482 
1483 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
1484 {
1485 	DBG_TRACE( "OutputDevice::DrawPixel()" );
1486 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1487 
1488 	Color aColor( rColor );
1489 
1490 	if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
1491 					   DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
1492                        DRAWMODE_SETTINGSLINE ) )
1493 	{
1494 		if( !ImplIsColorTransparent( aColor ) )
1495 		{
1496 			if( mnDrawMode & DRAWMODE_BLACKLINE )
1497 			{
1498 				aColor = Color( COL_BLACK );
1499 			}
1500 			else if( mnDrawMode & DRAWMODE_WHITELINE )
1501 			{
1502 				aColor = Color( COL_WHITE );
1503 			}
1504 			else if( mnDrawMode & DRAWMODE_GRAYLINE )
1505 			{
1506 				const sal_uInt8 cLum = aColor.GetLuminance();
1507 				aColor = Color( cLum, cLum, cLum );
1508 			}
1509             else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
1510             {
1511                 aColor = GetSettings().GetStyleSettings().GetFontColor();
1512             }
1513 
1514 			if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
1515 			{
1516 				aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
1517 								( aColor.GetGreen() >> 1 ) | 0x80,
1518 								( aColor.GetBlue() >> 1 ) | 0x80 );
1519 			}
1520 		}
1521 	}
1522 
1523 	if ( mpMetaFile )
1524 		mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
1525 
1526 	if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
1527 		return;
1528 
1529 	Point aPt = ImplLogicToDevicePixel( rPt );
1530 
1531 	// we need a graphics
1532 	if ( !mpGraphics )
1533 	{
1534 		if ( !ImplGetGraphics() )
1535 			return;
1536 	}
1537 
1538 	if ( mbInitClipRegion )
1539 		ImplInitClipRegion();
1540 	if ( mbOutputClipped )
1541 		return;
1542 
1543 	mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
1544 
1545     if( mpAlphaVDev )
1546         mpAlphaVDev->DrawPixel( rPt );
1547 }
1548 
1549 // -----------------------------------------------------------------------
1550 
1551 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
1552 {
1553 	if ( !pColors )
1554 		DrawPixel( rPts, GetLineColor() );
1555 	else
1556 	{
1557 		DBG_TRACE( "OutputDevice::DrawPixel()" );
1558 		DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1559 		DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
1560 
1561 		const sal_uInt16 nSize = rPts.GetSize();
1562 
1563 		if ( nSize )
1564 		{
1565 			if ( mpMetaFile )
1566 				for ( sal_uInt16 i = 0; i < nSize; i++ )
1567 					mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
1568 
1569 			if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1570 				return;
1571 
1572 			// we need a graphics
1573 			if ( mpGraphics || ImplGetGraphics() )
1574 			{
1575 				if ( mbInitClipRegion )
1576 					ImplInitClipRegion();
1577 
1578 				if ( mbOutputClipped )
1579 					return;
1580 
1581 				for ( sal_uInt16 i = 0; i < nSize; i++ )
1582 				{
1583 					const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
1584 					mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
1585 				}
1586 			}
1587 		}
1588 	}
1589 
1590     if( mpAlphaVDev )
1591         mpAlphaVDev->DrawPixel( rPts, pColors );
1592 }
1593 
1594 // -----------------------------------------------------------------------
1595 
1596 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
1597 {
1598 	if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
1599 	{
1600 		const sal_uInt16	nSize = rPts.GetSize();
1601 		Color*			pColArray = new Color[ nSize ];
1602 
1603 		for( sal_uInt16 i = 0; i < nSize; i++ )
1604 			pColArray[ i ] = rColor;
1605 
1606 		DrawPixel( rPts, pColArray );
1607 		delete[] pColArray;
1608 	}
1609 
1610     if( mpAlphaVDev )
1611         mpAlphaVDev->DrawPixel( rPts, rColor );
1612 }
1613 
1614 // ------------------------------------------------------------------------
1615 
1616 namespace
1617 {
1618     sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceOpaq, const sal_uInt8 nDestColor )
1619     {
1620         int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) )
1621             +     (int)nSourceOpaq * (int)nSourceColor;
1622         return sal_uInt8( c / 255 );
1623     }
1624 }
1625 
1626 // ------------------------------------------------------------------------
1627 
1628 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap              aBmp,
1629                                          BitmapReadAccess*	 pP,
1630                                          BitmapReadAccess*	 pA,
1631                                          const Rectangle&    aDstRect,
1632                                          const sal_Int32     nOffY,
1633                                          const sal_Int32     nDstHeight,
1634                                          const sal_Int32     nOffX,
1635                                          const sal_Int32     nDstWidth,
1636                                          const long*         pMapX,
1637                                          const long*         pMapY )
1638 {
1639     BitmapColor aDstCol,aSrcCol;
1640     Bitmap      res;
1641     int         nX, nOutX, nY, nOutY;
1642 
1643     OSL_ENSURE(mpAlphaVDev,
1644                "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
1645 
1646     sal_Bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1647     mpAlphaVDev->EnableMapMode(sal_False);
1648 
1649     Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1650     BitmapWriteAccess*	pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1651 
1652     if( GetBitCount() <= 8 )
1653     {
1654         Bitmap				aDither( aBmp.GetSizePixel(), 8 );
1655         BitmapColor 		aIndex( 0 );
1656         BitmapReadAccess*	pB = aBmp.AcquireReadAccess();
1657         BitmapWriteAccess*	pW = aDither.AcquireWriteAccess();
1658 
1659         if( pB && pP && pA && pW && pAlphaW )
1660         {
1661             for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1662             {
1663                 const long nMapY = pMapY[ nY ];
1664                 const long nModY = ( nOutY & 0x0FL ) << 4L;
1665 
1666                 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1667                 {
1668                     const long	nMapX = pMapX[ nX ];
1669                     const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1670 
1671                     aSrcCol = pP->GetColor( nMapY, nMapX );
1672                     aDstCol = pB->GetColor( nY, nX );
1673                     const sal_uInt8 nSrcOpaq = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1674                     const sal_uInt8 nDstOpaq  = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1675 
1676                     aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
1677                     aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
1678                     aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
1679 
1680                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1681                                               nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1682                                               nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1683                     pW->SetPixel( nY, nX, aIndex );
1684 
1685                     // Have to perform the compositing 'algebra' in
1686                     // the inverse alpha space (with 255 meaning
1687                     // opaque), otherwise, transitivity is not
1688                     // achieved.
1689                     const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
1690 
1691                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1692                                               nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1693                                               nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) );
1694                     pAlphaW->SetPixel( nY, nX, aIndex );
1695                 }
1696             }
1697         }
1698 
1699         aBmp.ReleaseAccess( pB );
1700         aDither.ReleaseAccess( pW );
1701         res = aDither;
1702     }
1703     else
1704     {
1705         BitmapWriteAccess*	pB = aBmp.AcquireWriteAccess();
1706         if( pP && pA && pB )
1707         {
1708             for( nY = 0; nY < nDstHeight; nY++ )
1709             {
1710                 const long	nMapY = pMapY[ nY ];
1711 
1712                 for( nX = 0; nX < nDstWidth; nX++ )
1713                 {
1714                     const long nMapX = pMapX[ nX ];
1715 
1716                     aSrcCol = pP->GetColor( nMapY, nMapX );
1717                     aDstCol = pB->GetColor( nY, nX );
1718                     const sal_uInt8 nSrcOpaq  = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1719                     const sal_uInt8 nDstOpaq  = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1720 
1721                     aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
1722                     aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
1723                     aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
1724 
1725                     pB->SetPixel( nY, nX, aDstCol );
1726 
1727                     // Have to perform the compositing 'algebra' in
1728                     // the inverse alpha space (with 255 meaning
1729                     // opaque), otherwise, transitivity is not
1730                     // achieved.
1731                     const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
1732 
1733                     pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) );
1734                 }
1735             }
1736         }
1737 
1738         aBmp.ReleaseAccess( pB );
1739         res = aBmp;
1740     }
1741 
1742     aAlphaBitmap.ReleaseAccess( pAlphaW );
1743     mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1744     mpAlphaVDev->EnableMapMode( bOldMapMode );
1745 
1746     return res;
1747 }
1748 
1749 // ------------------------------------------------------------------------
1750 
1751 Bitmap OutputDevice::ImplBlend( Bitmap              aBmp,
1752                                 BitmapReadAccess*	pP,
1753                                 BitmapReadAccess*	pA,
1754                                 const sal_Int32     nOffY,
1755                                 const sal_Int32     nDstHeight,
1756                                 const sal_Int32     nOffX,
1757                                 const sal_Int32     nDstWidth,
1758                                 const Rectangle&    aBmpRect,
1759                                 const Size&         aOutSz,
1760                                 const bool          bHMirr,
1761                                 const bool          bVMirr,
1762                                 const long*         pMapX,
1763                                 const long*         pMapY )
1764 {
1765     BitmapColor aDstCol;
1766     Bitmap      res;
1767     int         nX, nOutX, nY, nOutY;
1768 
1769     if( GetBitCount() <= 8 )
1770     {
1771         Bitmap				aDither( aBmp.GetSizePixel(), 8 );
1772         BitmapColor 		aIndex( 0 );
1773         BitmapReadAccess*	pB = aBmp.AcquireReadAccess();
1774         BitmapWriteAccess*	pW = aDither.AcquireWriteAccess();
1775 
1776         if( pB && pP && pA && pW )
1777         {
1778             for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1779             {
1780                 const long nMapY = pMapY[ nY ];
1781                 const long nModY = ( nOutY & 0x0FL ) << 4L;
1782 
1783                 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1784                 {
1785                     const long	nMapX = pMapX[ nX ];
1786                     const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1787 
1788                     aDstCol = pB->GetColor( nY, nX );
1789                     aDstCol.Merge( pP->GetColor( nMapY, nMapX ), (sal_uInt8) pA->GetPixel( nMapY, nMapX ) );
1790                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1791                                               nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1792                                               nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1793                     pW->SetPixel( nY, nX, aIndex );
1794                 }
1795             }
1796         }
1797 
1798         aBmp.ReleaseAccess( pB );
1799         aDither.ReleaseAccess( pW );
1800         res = aDither;
1801     }
1802     else
1803     {
1804         BitmapWriteAccess*	pB = aBmp.AcquireWriteAccess();
1805 
1806         bool bFastBlend = false;
1807         if( pP && pA && pB )
1808         {
1809             SalTwoRect aTR;
1810             aTR.mnSrcX      = aBmpRect.Left();
1811             aTR.mnSrcY      = aBmpRect.Top();
1812             aTR.mnSrcWidth  = aBmpRect.GetWidth();
1813             aTR.mnSrcHeight = aBmpRect.GetHeight();
1814             aTR.mnDestX     = nOffX;
1815             aTR.mnDestY     = nOffY;
1816             aTR.mnDestWidth = aOutSz.Width();
1817             aTR.mnDestHeight= aOutSz.Height();
1818 
1819             if( !bHMirr || !bVMirr )
1820                 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1821         }
1822 
1823         if( pP && pA && pB && !bFastBlend )
1824         {
1825             switch( pP->GetScanlineFormat() )
1826             {
1827                 case( BMP_FORMAT_8BIT_PAL ):
1828                     {
1829                         for( nY = 0; nY < nDstHeight; nY++ )
1830                         {
1831                             const long	nMapY = pMapY[ nY ];
1832                             Scanline	pPScan = pP->GetScanline( nMapY );
1833                             Scanline	pAScan = pA->GetScanline( nMapY );
1834 
1835                             for( nX = 0; nX < nDstWidth; nX++ )
1836                             {
1837                                 const long nMapX = pMapX[ nX ];
1838                                 aDstCol = pB->GetPixel( nY, nX );
1839                                 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
1840                                                                      pAScan[ nMapX ] ) );
1841                             }
1842                         }
1843                     }
1844                     break;
1845 
1846                 case( BMP_FORMAT_24BIT_TC_BGR ):
1847                     {
1848                         for( nY = 0; nY < nDstHeight; nY++ )
1849                         {
1850                             const long	nMapY = pMapY[ nY ];
1851                             Scanline	pPScan = pP->GetScanline( nMapY );
1852                             Scanline	pAScan = pA->GetScanline( nMapY );
1853 
1854                             for( nX = 0; nX < nDstWidth; nX++ )
1855                             {
1856                                 const long	nMapX = pMapX[ nX ];
1857                                 Scanline	pTmp = pPScan + nMapX * 3;
1858 
1859                                 aDstCol = pB->GetPixel( nY, nX );
1860                                 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
1861                                                                      pAScan[ nMapX ] ) );
1862                             }
1863                         }
1864                     }
1865                     break;
1866 
1867                 case( BMP_FORMAT_24BIT_TC_RGB ):
1868                     {
1869                         for( nY = 0; nY < nDstHeight; nY++ )
1870                         {
1871                             const long	nMapY = pMapY[ nY ];
1872                             Scanline	pPScan = pP->GetScanline( nMapY );
1873                             Scanline	pAScan = pA->GetScanline( nMapY );
1874 
1875                             for( nX = 0; nX < nDstWidth; nX++ )
1876                             {
1877                                 const long	nMapX = pMapX[ nX ];
1878                                 Scanline    pTmp = pPScan + nMapX * 3;
1879 
1880                                 aDstCol = pB->GetPixel( nY, nX );
1881                                 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
1882                                                                      pAScan[ nMapX ] ) );
1883                             }
1884                         }
1885                     }
1886                     break;
1887 
1888                 default:
1889                 {
1890                     for( nY = 0; nY < nDstHeight; nY++ )
1891                     {
1892                         const long	nMapY = pMapY[ nY ];
1893                         Scanline	pAScan = pA->GetScanline( nMapY );
1894 
1895                         for( nX = 0; nX < nDstWidth; nX++ )
1896                         {
1897                             const long nMapX = pMapX[ nX ];
1898                             aDstCol = pB->GetPixel( nY, nX );
1899                             pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
1900                                                                  pAScan[ nMapX ] ) );
1901                         }
1902                     }
1903                 }
1904                 break;
1905             }
1906         }
1907 
1908         aBmp.ReleaseAccess( pB );
1909         res = aBmp;
1910     }
1911 
1912     return res;
1913 }
1914 
1915 // ------------------------------------------------------------------------
1916 
1917 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
1918 								  const Point& rDestPt, const Size& rDestSize,
1919 								  const Point& rSrcPtPixel, const Size& rSrcSizePixel )
1920 {
1921 	const Point aNullPt;
1922 	Point		aOutPt( LogicToPixel( rDestPt ) );
1923 	Size        aOutSz( LogicToPixel( rDestSize ) );
1924 	Rectangle	aDstRect( aNullPt, GetOutputSizePixel() );
1925 	const sal_Bool	bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0;
1926 
1927 	if( OUTDEV_WINDOW == meOutDevType )
1928 	{
1929 		const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
1930 
1931 		if( !aPaintRgn.IsNull() )
1932 			aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
1933 	}
1934 
1935 	if( bHMirr )
1936 	{
1937 		aOutSz.Width() = -aOutSz.Width();
1938 		aOutPt.X() -= ( aOutSz.Width() - 1L );
1939 	}
1940 
1941 	if( bVMirr )
1942 	{
1943 		aOutSz.Height() = -aOutSz.Height();
1944 		aOutPt.Y() -= ( aOutSz.Height() - 1L );
1945 	}
1946 
1947 	if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
1948 	{
1949         bool bNativeAlpha = false;
1950         static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
1951         // #i83087# Naturally, system alpha blending cannot work with
1952         // separate alpha VDev
1953         if( !mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr )
1954         {
1955             Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
1956             SalTwoRect aTR = {
1957                 rSrcPtPixel.X(), rSrcPtPixel.Y(),
1958                 rSrcSizePixel.Width(), rSrcSizePixel.Height(),
1959                 aRelPt.X(), aRelPt.Y(),
1960                 aOutSz.Width(), aOutSz.Height()
1961             };
1962             SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
1963             SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
1964             bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
1965         }
1966 
1967         VirtualDevice* pOldVDev = mpAlphaVDev;
1968 
1969 		Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
1970 		if( !bNativeAlpha
1971                 &&  !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
1972 		{
1973 			GDIMetaFile*	pOldMetaFile = mpMetaFile; mpMetaFile = NULL;
1974 			const sal_Bool		bOldMap = mbMap; mbMap = sal_False;
1975 			Bitmap			aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1976 
1977             // #109044# The generated bitmap need not necessarily be
1978             // of aDstRect dimensions, it's internally clipped to
1979             // window bounds. Thus, we correct the dest size here,
1980             // since we later use it (in nDstWidth/Height) for pixel
1981             // access)
1982             // #i38887# reading from screen may sometimes fail
1983             if( aBmp.ImplGetImpBitmap() )
1984                 aDstRect.SetSize( aBmp.GetSizePixel() );
1985 
1986 			BitmapColor 	aDstCol;
1987 			const long		nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
1988 			const long		nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
1989 			const long		nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
1990 			// calculate offset in original bitmap
1991 			// in RTL case this is a little more complicated since the contents of the
1992 			// bitmap is not mirrored (it never is), however the paint region and bmp region
1993 			// are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
1994 			// is content wise somewhere else and needs to take mirroring into account
1995 			const long		nOffX = IsRTLEnabled()
1996 			                        ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
1997 			                        : aDstRect.Left() - aOutPt.X(),
1998 				            nOffY = aDstRect.Top() - aOutPt.Y();
1999 			long			nX, nOutX, nY, nOutY;
2000 			long			nMirrOffX = 0;
2001 			long			nMirrOffY = 0;
2002 			long*			pMapX = new long[ nDstWidth ];
2003 			long*			pMapY = new long[ nDstHeight ];
2004 
2005 			// create horizontal mapping table
2006 			if( bHMirr )
2007 				nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
2008 
2009 			for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2010 			{
2011 				pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
2012 				if( bHMirr )
2013 					pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
2014 			}
2015 
2016 			// create vertical mapping table
2017 			if( bVMirr )
2018 				nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
2019 
2020 			for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2021 			{
2022 				pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
2023 
2024 				if( bVMirr )
2025 					pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
2026 			}
2027 
2028             BitmapReadAccess*	pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
2029             BitmapReadAccess*	pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
2030 
2031             DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
2032                         pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
2033                         "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
2034 
2035             // #i38887# reading from screen may sometimes fail
2036             if( aBmp.ImplGetImpBitmap() )
2037             {
2038                 Bitmap aTmp;
2039 
2040                 if( mpAlphaVDev )
2041                 {
2042                     aTmp = ImplBlendWithAlpha(
2043                         aBmp,pP,pA,
2044                         aDstRect,
2045                         nOffY,nDstHeight,
2046                         nOffX,nDstWidth,
2047                         pMapX,pMapY );
2048                 }
2049                 else
2050                 {
2051                     aTmp = ImplBlend(
2052                         aBmp,pP,pA,
2053                         nOffY,nDstHeight,
2054                         nOffX,nDstWidth,
2055                         aBmpRect,aOutSz,
2056                         bHMirr,bVMirr,
2057                         pMapX,pMapY );
2058                 }
2059 
2060                 // #110958# Disable alpha VDev, we're doing the necessary
2061                 // stuff explicitely furher below
2062                 if( mpAlphaVDev )
2063                     mpAlphaVDev = NULL;
2064 
2065                 DrawBitmap( aDstRect.TopLeft(),
2066                             aTmp );
2067 
2068                 // #110958# Enable alpha VDev again
2069                 mpAlphaVDev = pOldVDev;
2070             }
2071 
2072             ( (Bitmap&) rBmp ).ReleaseAccess( pP );
2073             ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
2074 
2075 			delete[] pMapX;
2076 			delete[] pMapY;
2077 			mbMap = bOldMap;
2078 			mpMetaFile = pOldMetaFile;
2079 		}
2080 	}
2081 }
2082 
2083 // ------------------------------------------------------------------------
2084 
2085 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
2086 										 const Point& rDestPt, const Size& rDestSize,
2087 										 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2088 {
2089 	Point		aPt;
2090 	Point		aDestPt( LogicToPixel( rDestPt ) );
2091 	Size		aDestSz( LogicToPixel( rDestSize ) );
2092 	Rectangle	aSrcRect( rSrcPtPixel, rSrcSizePixel );
2093 
2094 	aSrcRect.Justify();
2095 
2096 	if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2097 	{
2098 		Bitmap	aPaint( rBmp ), aMask( rMask );
2099 		sal_uLong	nMirrFlags = 0UL;
2100 
2101 		if( aMask.GetBitCount() > 1 )
2102 			aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2103 
2104 		// mirrored horizontically
2105 		if( aDestSz.Width() < 0L )
2106 		{
2107 			aDestSz.Width() = -aDestSz.Width();
2108 			aDestPt.X() -= ( aDestSz.Width() - 1L );
2109 			nMirrFlags |= BMP_MIRROR_HORZ;
2110 		}
2111 
2112 		// mirrored vertically
2113 		if( aDestSz.Height() < 0L )
2114 		{
2115 			aDestSz.Height() = -aDestSz.Height();
2116 			aDestPt.Y() -= ( aDestSz.Height() - 1L );
2117 			nMirrFlags |= BMP_MIRROR_VERT;
2118 		}
2119 
2120 		// source cropped?
2121 		if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
2122 		{
2123 			aPaint.Crop( aSrcRect );
2124 			aMask.Crop( aSrcRect );
2125 		}
2126 
2127 		// destination mirrored
2128 		if( nMirrFlags )
2129 		{
2130 			aPaint.Mirror( nMirrFlags );
2131 			aMask.Mirror( nMirrFlags );
2132 		}
2133 
2134 		// we always want to have a mask
2135 		if( aMask.IsEmpty() )
2136 		{
2137 			aMask = Bitmap( aSrcRect.GetSize(), 1 );
2138 			aMask.Erase( Color( COL_BLACK ) );
2139 		}
2140 
2141 		// do painting
2142         const long		nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2143 		long			nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2144 		long*			pMapX = new long[ nSrcWidth + 1 ];
2145 		long*			pMapY = new long[ nSrcHeight + 1 ];
2146 		const sal_Bool		bOldMap = mbMap;
2147 
2148 		mbMap = sal_False;
2149 
2150 		// create forward mapping tables
2151 		for( nX = 0L; nX <= nSrcWidth; nX++ )
2152 			pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2153 
2154 		for( nY = 0L; nY <= nSrcHeight; nY++ )
2155 			pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2156 
2157         // walk through all rectangles of mask
2158         Region          aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2159 		ImplRegionInfo	aInfo;
2160 		sal_Bool            bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2161 
2162 		while( bRgnRect )
2163 		{
2164 			Bitmap          aBandBmp( aPaint );
2165             const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) );
2166             const Point     aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2167             const Size      aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2168 
2169 			aBandBmp.Crop( aBandRect );
2170             ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION );
2171             bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2172 		}
2173 
2174         mbMap = bOldMap;
2175 
2176         delete[] pMapX;
2177         delete[] pMapY;
2178 	}
2179 }
2180 
2181 // ------------------------------------------------------------------------
2182 
2183 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
2184 								  const Point& rDestPt, const Size& rDestSize,
2185 								  const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2186 {
2187     Point		aPt;
2188 	Point		aDestPt( LogicToPixel( rDestPt ) );
2189 	Size		aDestSz( LogicToPixel( rDestSize ) );
2190 	Rectangle	aSrcRect( rSrcPtPixel, rSrcSizePixel );
2191 
2192 	aSrcRect.Justify();
2193 
2194 	if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2195 	{
2196 		Bitmap	aMask( rMask );
2197 		sal_uLong	nMirrFlags = 0UL;
2198 
2199 		if( aMask.GetBitCount() > 1 )
2200 			aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2201 
2202 		// mirrored horizontically
2203 		if( aDestSz.Width() < 0L )
2204 		{
2205 			aDestSz.Width() = -aDestSz.Width();
2206 			aDestPt.X() -= ( aDestSz.Width() - 1L );
2207 			nMirrFlags |= BMP_MIRROR_HORZ;
2208 		}
2209 
2210 		// mirrored vertically
2211 		if( aDestSz.Height() < 0L )
2212 		{
2213 			aDestSz.Height() = -aDestSz.Height();
2214 			aDestPt.Y() -= ( aDestSz.Height() - 1L );
2215 			nMirrFlags |= BMP_MIRROR_VERT;
2216 		}
2217 
2218 		// source cropped?
2219 		if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) )
2220 			aMask.Crop( aSrcRect );
2221 
2222 		// destination mirrored
2223 		if( nMirrFlags )
2224 			aMask.Mirror( nMirrFlags );
2225 
2226 		// do painting
2227         const long		nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2228 		long			nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2229 		long*			pMapX = new long[ nSrcWidth + 1 ];
2230 		long*			pMapY = new long[ nSrcHeight + 1 ];
2231         GDIMetaFile*    pOldMetaFile = mpMetaFile;
2232 		const sal_Bool		bOldMap = mbMap;
2233 
2234 		mpMetaFile = NULL;
2235 		mbMap = sal_False;
2236 		Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
2237 		SetLineColor( rMaskColor );
2238 		SetFillColor( rMaskColor );
2239 		ImplInitLineColor();
2240 		ImplInitFillColor();
2241 
2242 		// create forward mapping tables
2243 		for( nX = 0L; nX <= nSrcWidth; nX++ )
2244 			pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2245 
2246 		for( nY = 0L; nY <= nSrcHeight; nY++ )
2247 			pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2248 
2249         // walk through all rectangles of mask
2250         Region          aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2251 		ImplRegionInfo	aInfo;
2252 		sal_Bool            bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2253 
2254 		while( bRgnRect )
2255 		{
2256             const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2257             const Size  aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2258 
2259 			DrawRect( Rectangle( aMapPt, aMapSz ) );
2260 			bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2261 		}
2262 
2263 		Pop();
2264 		delete[] pMapX;
2265 		delete[] pMapY;
2266 		mbMap = bOldMap;
2267 		mpMetaFile = pOldMetaFile;
2268 	}
2269 }
2270