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