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