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