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