xref: /trunk/main/vcl/source/gdi/outdev6.cxx (revision 9f62ea84)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <tools/debug.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/bmpacc.hxx>
31 #include <vcl/metaact.hxx>
32 #include <vcl/gdimtf.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/wrkwin.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/rendergraphicrasterizer.hxx>
37 
38 #include <wall2.hxx>
39 #include <salgdi.hxx>
40 #include <window.h>
41 #include <svdata.hxx>
42 #include <outdev.h>
43 
44 #include <com/sun/star/uno/Sequence.hxx>
45 
46 #include <basegfx/vector/b2dvector.hxx>
47 #include <basegfx/polygon/b2dpolypolygon.hxx>
48 #include <basegfx/polygon/b2dpolygon.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 
51 #include <math.h>
52 
53 // ========================================================================
54 
55 DBG_NAMEEX( OutputDevice )
56 
57 // ------------------------------------------------------------------------
58 
59 void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLong nFlags )
60 {
61 	DBG_TRACE( "OutputDevice::DrawGrid()" );
62 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
63 
64 	Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() );
65 	aDstRect.Intersection( rRect );
66 
67 	if( aDstRect.IsEmpty() || ImplIsRecordLayout() )
68 		return;
69 
70 	if( !mpGraphics && !ImplGetGraphics() )
71 		return;
72 
73 	if( mbInitClipRegion )
74 		ImplInitClipRegion();
75 
76 	if( mbOutputClipped )
77 		return;
78 
79 	const long	nDistX = Max( rDist.Width(), 1L );
80 	const long	nDistY = Max( rDist.Height(), 1L );
81 	long		nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX );
82 	long		nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY );
83 	const long	nRight = aDstRect.Right();
84 	const long	nBottom = aDstRect.Bottom();
85 	const long	nStartX = ImplLogicXToDevicePixel( nX );
86 	const long	nEndX = ImplLogicXToDevicePixel( nRight );
87 	const long	nStartY = ImplLogicYToDevicePixel( nY );
88 	const long	nEndY = ImplLogicYToDevicePixel( nBottom );
89 	long		nHorzCount = 0L;
90 	long		nVertCount = 0L;
91 
92 	::com::sun::star::uno::Sequence< sal_Int32 > aVertBuf;
93 	::com::sun::star::uno::Sequence< sal_Int32 > aHorzBuf;
94 
95 	if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_HORZLINES ) )
96 	{
97 		aVertBuf.realloc( aDstRect.GetHeight() / nDistY + 2L );
98 		aVertBuf[ nVertCount++ ] = nStartY;
99 		while( ( nY += nDistY ) <= nBottom )
100 			aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY );
101 	}
102 
103 	if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_VERTLINES ) )
104 	{
105 		aHorzBuf.realloc( aDstRect.GetWidth() / nDistX + 2L );
106 		aHorzBuf[ nHorzCount++ ] = nStartX;
107 		while( ( nX += nDistX ) <= nRight )
108 			aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX );
109 	}
110 
111 	if( mbInitLineColor )
112 		ImplInitLineColor();
113 
114 	if( mbInitFillColor )
115 		ImplInitFillColor();
116 
117 	const sal_Bool bOldMap = mbMap;
118 	EnableMapMode( sal_False );
119 
120 	if( nFlags & GRID_DOTS )
121 	{
122 		for( long i = 0L; i < nVertCount; i++ )
123 			for( long j = 0L, Y = aVertBuf[ i ]; j < nHorzCount; j++ )
124 				mpGraphics->DrawPixel( aHorzBuf[ j ], Y, this );
125 	}
126 	else
127 	{
128 		if( nFlags & GRID_HORZLINES )
129 		{
130 			for( long i = 0L; i < nVertCount; i++ )
131 			{
132 				nY = aVertBuf[ i ];
133 				mpGraphics->DrawLine( nStartX, nY, nEndX, nY, this );
134 			}
135 		}
136 
137 		if( nFlags & GRID_VERTLINES )
138 		{
139 			for( long i = 0L; i < nHorzCount; i++ )
140 			{
141 				nX = aHorzBuf[ i ];
142 				mpGraphics->DrawLine( nX, nStartY, nX, nEndY, this );
143 			}
144 		}
145 	}
146 
147 	EnableMapMode( bOldMap );
148 
149     if( mpAlphaVDev )
150         mpAlphaVDev->DrawGrid( rRect, rDist, nFlags );
151 }
152 
153 // ------------------------------------------------------------------------
154 // Caution: This method is nearly the same as
155 // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
156 // so when changes are made here do not forget to make change sthere, too
157 
158 void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency)
159 {
160 	DBG_TRACE( "OutputDevice::DrawTransparent(B2D&,transparency)" );
161 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
162 
163     // AW: Do NOT paint empty PolyPolygons
164     if(!rB2DPolyPoly.count())
165         return;
166 
167     // we need a graphics
168     if( !mpGraphics )
169 	    if( !ImplGetGraphics() )
170 		    return;
171 
172     if( mbInitClipRegion )
173 	    ImplInitClipRegion();
174     if( mbOutputClipped )
175 	    return;
176 
177     if( mbInitLineColor )
178 	    ImplInitLineColor();
179     if( mbInitFillColor )
180 	    ImplInitFillColor();
181 
182 	if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
183 		&& mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
184 		&& ROP_OVERPAINT == GetRasterOp() )
185     {
186         // b2dpolygon support not implemented yet on non-UNX platforms
187         const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
188         basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
189 
190 		// transform the polygon into device space and ensure it is closed
191 		aB2DPolyPolygon.transform( aTransform );
192 		aB2DPolyPolygon.setClosed( true );
193 
194 		bool bDrawnOk = true;
195 		if( IsFillColor() )
196 			bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
197 		if( bDrawnOk && IsLineColor() )
198 		{
199 			const basegfx::B2DVector aHairlineWidth(1,1);
200 			const int nPolyCount = aB2DPolyPolygon.count();
201 			for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
202 			{
203 				const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
204 				mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, this );
205 			}
206 		}
207 
208         if( bDrawnOk )
209         {
210 #if 0
211             // MetaB2DPolyPolygonAction is not implemented yet:
212             // according to AW adding it is very dangerous since there is a lot
213             // of code that uses the metafile actions directly and unless every
214             // place that does this knows about the new action we need to fallback
215             if( mpMetaFile )
216                 mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) );
217 #else
218             if( mpMetaFile )
219     	        mpMetaFile->AddAction( new MetaTransparentAction( PolyPolygon( rB2DPolyPoly ), static_cast< sal_uInt16 >(fTransparency * 100.0)));
220 #endif
221             return;
222         }
223     }
224 
225     // fallback to old polygon drawing if needed
226     const PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
227     DrawTransparent(PolyPolygon(rB2DPolyPoly), static_cast< sal_uInt16 >(fTransparency * 100.0));
228 }
229 
230 // ------------------------------------------------------------------------
231 
232 void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
233 									sal_uInt16 nTransparencePercent )
234 {
235 	DBG_TRACE( "OutputDevice::DrawTransparent()" );
236 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
237 
238 	// short circuit for drawing an opaque polygon
239 	if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) )
240 	{
241 		DrawPolyPolygon( rPolyPoly );
242 		return;
243 	}
244 
245 	// short circut for drawing an invisible polygon
246 	if( !mbFillColor || (nTransparencePercent >= 100) )
247 	{
248 		// short circuit if the polygon border is invisible too
249 		if( !mbLineColor )
250 			return;
251 
252 		// DrawTransparent() assumes that the border is NOT to be drawn transparently???
253 		Push( PUSH_FILLCOLOR );
254 		SetFillColor();
255 		DrawPolyPolygon( rPolyPoly );
256 		Pop();
257 		return;
258 	}
259 
260 	// handle metafile recording
261 	if( mpMetaFile )
262 		mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
263 
264     bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
265     if( bDrawn )
266 		return;
267 
268 	// get the device graphics as drawing target
269 	if( !mpGraphics )
270 		if( !ImplGetGraphics() )
271 			return;
272 
273     // debug helper:
274     static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
275 
276     // try hard to draw it directly, because the emulation layers are slower
277 	if( !pDisableNative
278 	    && mpGraphics->supportsOperation( OutDevSupport_B2DDraw )
279 #if defined UNX && ! defined QUARTZ
280             && GetBitCount() > 8
281 #endif
282 #ifdef WIN32
283         // workaround bad dithering on remote displaying when using GDI+ with toolbar buttoin hilighting
284         && !rPolyPoly.IsRect()
285 #endif
286         )
287 	{
288 		// prepare the graphics device
289 		if( mbInitClipRegion )
290 			ImplInitClipRegion();
291         if( mbOutputClipped )
292 			return;
293 		if( mbInitLineColor )
294 			ImplInitLineColor();
295 		if( mbInitFillColor )
296 			ImplInitFillColor();
297 
298 		// get the polygon in device coordinates
299 		basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() );
300 		const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
301 		aB2DPolyPolygon.transform( aTransform );
302 
303 		const double fTransparency = 0.01 * nTransparencePercent;
304 		if( mbFillColor )
305 		{
306 			// draw the transparent polygon
307 			// NOTE: filled polygons are assumed to be drawn as if they were always closed
308 			bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
309 		}
310 
311 		if( mbLineColor )
312 		{
313 			// disable the fill color for now
314 			mpGraphics->SetFillColor();
315 			// draw the border line
316 			const basegfx::B2DVector aLineWidths( 1, 1 );
317 			const int nPolyCount = aB2DPolyPolygon.count();
318 			for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
319 			{
320 				const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
321 				bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, this );
322 			}
323 			// prepare to restore the fill color
324 			mbInitFillColor = mbFillColor;
325 		}
326 	}
327 
328 	if( bDrawn )
329 		return;
330 
331 	if( 1 )
332 	{
333         VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
334 
335         // #110958# Disable alpha VDev, we perform the necessary
336         // operation explicitely further below.
337         if( mpAlphaVDev )
338             mpAlphaVDev = NULL;
339 
340 		GDIMetaFile* pOldMetaFile = mpMetaFile;
341 		mpMetaFile = NULL;
342 
343 		if( OUTDEV_PRINTER == meOutDevType )
344 		{
345 			if(100 <= nTransparencePercent)
346 			{
347 				// #i112959# 100% transparent, draw nothing
348 				return;
349 			}
350 
351 			Rectangle		aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
352 			const Size		aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
353 			const long		nBaseExtent = Max( FRound( aDPISize.Width() / 300. ), 1L );
354 			long			nMove;
355 			const sal_uInt16	nTrans = ( nTransparencePercent < 13 ) ? 0 :
356 									 ( nTransparencePercent < 38 ) ? 25 :
357 									 ( nTransparencePercent < 63 ) ? 50 :
358 									 ( nTransparencePercent < 88 ) ? 75 : 100;
359 
360 			switch( nTrans )
361 			{
362 				case( 25 ): nMove = nBaseExtent * 3; break;
363 				case( 50 ): nMove = nBaseExtent * 4; break;
364 				case( 75 ): nMove = nBaseExtent * 6; break;
365 
366 				// #i112959#  very transparent (88 < nTransparencePercent <= 99)
367 				case( 100 ): nMove = nBaseExtent * 8; break;
368 
369 				// #i112959# not transparent (nTransparencePercent < 13)
370 				default:    nMove = 0; break;
371 			}
372 
373 			Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
374 			IntersectClipRegion( rPolyPoly );
375 			SetLineColor( GetFillColor() );
376 			const sal_Bool bOldMap = mbMap;
377 			EnableMapMode( sal_False );
378 
379 			if(nMove)
380 			{
381 				Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
382 				while( aRect.Top() <= aPolyRect.Bottom() )
383 				{
384 					DrawRect( aRect );
385 					aRect.Move( 0, nMove );
386 				}
387 
388 				aRect = Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
389 				while( aRect.Left() <= aPolyRect.Right() )
390 				{
391 					DrawRect( aRect );
392 					aRect.Move( nMove, 0 );
393 				}
394 			}
395 			else
396 			{
397 				// #i112959# if not transparent, draw full rectangle in clip region
398 				DrawRect( aPolyRect );
399 			}
400 
401 			EnableMapMode( bOldMap );
402 			Pop();
403 		}
404 		else
405 		{
406  			PolyPolygon 	aPolyPoly( LogicToPixel( rPolyPoly ) );
407 			Rectangle		aPolyRect( aPolyPoly.GetBoundRect() );
408 			Point			aPoint;
409 			Rectangle		aDstRect( aPoint, GetOutputSizePixel() );
410 
411 			aDstRect.Intersection( aPolyRect );
412 
413 			if( OUTDEV_WINDOW == meOutDevType )
414 			{
415 				const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
416 
417 				if( !aPaintRgn.IsNull() )
418 					aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() );
419 			}
420 
421 			if( !aDstRect.IsEmpty() )
422 			{
423                 // #i66849# Added fast path for exactly rectangular
424                 // polygons
425                 // #i83087# Naturally, system alpha blending cannot
426                 // work with separate alpha VDev
427                 if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() )
428                 {
429                     // setup Graphics only here (other cases delegate
430                     // to basic OutDev methods)
431                     if( 1 )
432                     {
433                         if ( mbInitClipRegion )
434                             ImplInitClipRegion();
435                         if ( mbInitLineColor )
436                             ImplInitLineColor();
437                         if ( mbInitFillColor )
438                             ImplInitFillColor();
439 
440                         Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
441                         Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
442 
443                         if( !mbOutputClipped )
444                         {
445                             bDrawn = mpGraphics->DrawAlphaRect(
446                                aPixelRect.Left(), aPixelRect.Top(),
447                                // #i98405# use methods with small g, else one pixel too much will be painted.
448                                // This is because the source is a polygon which when painted would not paint
449                                // the rightmost and lowest pixel line(s), so use one pixel less for the
450                                // rectangle, too.
451                                aPixelRect.getWidth(), aPixelRect.getHeight(),
452                                sal::static_int_cast<sal_uInt8>(nTransparencePercent),
453                                this );
454                         }
455                         else
456                             bDrawn = true;
457                     }
458                 }
459 
460                 if( !bDrawn )
461                 {
462                     VirtualDevice	aVDev( *this, 1 );
463                     const Size		aDstSz( aDstRect.GetSize() );
464                     const sal_uInt8		cTrans = (sal_uInt8) MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 );
465 
466                     if( aDstRect.Left() || aDstRect.Top() )
467                         aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
468 
469                     if( aVDev.SetOutputSizePixel( aDstSz ) )
470                     {
471                         const sal_Bool bOldMap = mbMap;
472 
473                         EnableMapMode( sal_False );
474 
475                         aVDev.SetLineColor( COL_BLACK );
476                         aVDev.SetFillColor( COL_BLACK );
477                         aVDev.DrawPolyPolygon( aPolyPoly );
478 
479                         Bitmap				aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
480                         Bitmap				aPolyMask( aVDev.GetBitmap( Point(), aDstSz ) );
481 
482                         // #107766# check for non-empty bitmaps before accessing them
483                         if( !!aPaint && !!aPolyMask )
484                         {
485                             BitmapWriteAccess*	pW = aPaint.AcquireWriteAccess();
486                             BitmapReadAccess*	pR = aPolyMask.AcquireReadAccess();
487 
488                             if( pW && pR )
489                             {
490                                 BitmapColor 		aPixCol;
491                                 const BitmapColor	aFillCol( GetFillColor() );
492                                 const BitmapColor	aWhite( pR->GetBestMatchingColor( Color( COL_WHITE ) ) );
493                                 const BitmapColor	aBlack( pR->GetBestMatchingColor( Color( COL_BLACK ) ) );
494                                 const long			nWidth = pW->Width(), nHeight = pW->Height();
495                                 const long			nR = aFillCol.GetRed(), nG = aFillCol.GetGreen(), nB = aFillCol.GetBlue();
496                                 long				nX, nY;
497 
498                                 if( aPaint.GetBitCount() <= 8 )
499                                 {
500                                     const BitmapPalette&	rPal = pW->GetPalette();
501                                     const sal_uInt16			nCount = rPal.GetEntryCount();
502                                     BitmapColor*			pMap = (BitmapColor*) new sal_uInt8[ nCount * sizeof( BitmapColor ) ];
503 
504                                     for( sal_uInt16 i = 0; i < nCount; i++ )
505                                     {
506                                         BitmapColor aCol( rPal[ i ] );
507                                         pMap[ i ] = BitmapColor( (sal_uInt8) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) );
508                                     }
509 
510                                     if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
511                                         pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
512                                     {
513                                         const sal_uInt8 cBlack = aBlack.GetIndex();
514 
515                                         for( nY = 0; nY < nHeight; nY++ )
516                                         {
517                                             Scanline	pWScan = pW->GetScanline( nY );
518                                             Scanline	pRScan = pR->GetScanline( nY );
519                                             sal_uInt8		cBit = 128;
520 
521                                             for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
522                                             {
523                                                 if( !cBit )
524                                                     cBit = 128, pRScan++;
525 
526                                                 if( ( *pRScan & cBit ) == cBlack )
527                                                     *pWScan = (sal_uInt8) pMap[ *pWScan ].GetIndex();
528                                             }
529                                         }
530                                     }
531                                     else
532                                     {
533                                         for( nY = 0; nY < nHeight; nY++ )
534                                             for( nX = 0; nX < nWidth; nX++ )
535                                                 if( pR->GetPixel( nY, nX ) == aBlack )
536                                                     pW->SetPixel( nY, nX, pMap[ pW->GetPixel( nY, nX ).GetIndex() ] );
537                                     }
538 
539                                     delete[] (sal_uInt8*) pMap;
540                                 }
541                                 else
542                                 {
543                                     if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
544                                         pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
545                                     {
546                                         const sal_uInt8 cBlack = aBlack.GetIndex();
547 
548                                         for( nY = 0; nY < nHeight; nY++ )
549                                         {
550                                             Scanline	pWScan = pW->GetScanline( nY );
551                                             Scanline	pRScan = pR->GetScanline( nY );
552                                             sal_uInt8		cBit = 128;
553 
554                                             for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
555                                             {
556                                                 if( !cBit )
557                                                     cBit = 128, pRScan++;
558 
559                                                 if( ( *pRScan & cBit ) == cBlack )
560                                                 {
561                                                     pWScan[ 0 ] = COLOR_CHANNEL_MERGE( pWScan[ 0 ], nB, cTrans );
562                                                     pWScan[ 1 ] = COLOR_CHANNEL_MERGE( pWScan[ 1 ], nG, cTrans );
563                                                     pWScan[ 2 ] = COLOR_CHANNEL_MERGE( pWScan[ 2 ], nR, cTrans );
564                                                 }
565                                             }
566                                         }
567                                     }
568                                     else
569                                     {
570                                         for( nY = 0; nY < nHeight; nY++ )
571                                         {
572                                             for( nX = 0; nX < nWidth; nX++ )
573                                             {
574                                                 if( pR->GetPixel( nY, nX ) == aBlack )
575                                                 {
576                                                     aPixCol = pW->GetColor( nY, nX );
577                                                     pW->SetPixel( nY, nX, aPixCol.Merge( aFillCol, cTrans ) );
578                                                 }
579                                             }
580                                         }
581                                     }
582                                 }
583                             }
584 
585                             aPolyMask.ReleaseAccess( pR );
586                             aPaint.ReleaseAccess( pW );
587 
588                             DrawBitmap( aDstRect.TopLeft(), aPaint );
589 
590                             EnableMapMode( bOldMap );
591 
592                             if( mbLineColor )
593                             {
594                                 Push( PUSH_FILLCOLOR );
595                                 SetFillColor();
596                                 DrawPolyPolygon( rPolyPoly );
597                                 Pop();
598                             }
599                         }
600                     }
601                     else
602                         DrawPolyPolygon( rPolyPoly );
603                 }
604             }
605         }
606 
607 		mpMetaFile = pOldMetaFile;
608 
609         // #110958# Restore disabled alpha VDev
610         mpAlphaVDev = pOldAlphaVDev;
611 
612         // #110958# Apply alpha value also to VDev alpha channel
613         if( mpAlphaVDev )
614         {
615             const Color aFillCol( mpAlphaVDev->GetFillColor() );
616             mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
617                                              sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
618                                              sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
619 
620             mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
621 
622             mpAlphaVDev->SetFillColor( aFillCol );
623         }
624 	}
625 }
626 
627 // -----------------------------------------------------------------------
628 
629 void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
630 									const Size& rSize, const Gradient& rTransparenceGradient )
631 {
632 	DBG_TRACE( "OutputDevice::DrawTransparent()" );
633 	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
634 
635 	const Color aBlack( COL_BLACK );
636 
637 	if( mpMetaFile )
638 		mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
639 
640 	if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
641 		( mnDrawMode & ( DRAWMODE_NOTRANSPARENCY ) ) )
642 	{
643 		( (GDIMetaFile&) rMtf ).WindStart();
644 		( (GDIMetaFile&) rMtf ).Play( this, rPos, rSize );
645 		( (GDIMetaFile&) rMtf ).WindStart();
646 	}
647 	else
648 	{
649 		GDIMetaFile*	pOldMetaFile = mpMetaFile;
650 		Rectangle		aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
651 		Point			aPoint;
652 		Rectangle		aDstRect( aPoint, GetOutputSizePixel() );
653 
654 		mpMetaFile = NULL;
655 		aDstRect.Intersection( aOutRect );
656 
657 		if( OUTDEV_WINDOW == meOutDevType )
658 		{
659 			const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
660 
661 			if( !aPaintRgn.IsNull() )
662 				aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
663 		}
664 
665 		if( !aDstRect.IsEmpty() )
666 		{
667 			VirtualDevice* pVDev = new VirtualDevice;
668 
669 			((OutputDevice*)pVDev)->mnDPIX = mnDPIX;
670 			((OutputDevice*)pVDev)->mnDPIY = mnDPIY;
671 
672 			if( pVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
673 			{
674 				if(GetAntialiasing())
675 				{
676 					// #i102109#
677 					// For MetaFile replay (see task) it may now be neccessary to take
678 					// into account that the content is AntiAlialised and needs to be masked
679 					// like that. Instead of masking, i will use a copy-modify-paste cycle
680 					// here (as i already use in the VclPrimiziveRenderer with successs)
681 					pVDev->SetAntialiasing(GetAntialiasing());
682 
683 					// create MapMode for buffer (offset needed) and set
684 					MapMode aMap(GetMapMode());
685 					const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
686 					aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
687 					pVDev->SetMapMode(aMap);
688 
689 					// copy MapMode state and disable for target
690 					const bool bOrigMapModeEnabled(IsMapModeEnabled());
691 					EnableMapMode(false);
692 
693 					// copy MapMode state and disable for buffer
694 					const bool bBufferMapModeEnabled(pVDev->IsMapModeEnabled());
695 					pVDev->EnableMapMode(false);
696 
697 					// copy content from original to buffer
698 					pVDev->DrawOutDev(
699 						aPoint, pVDev->GetOutputSizePixel(), // dest
700 						aDstRect.TopLeft(), pVDev->GetOutputSizePixel(), // source
701 						*this);
702 
703 					// draw MetaFile to buffer
704 					pVDev->EnableMapMode(bBufferMapModeEnabled);
705 					((GDIMetaFile&)rMtf).WindStart();
706 					((GDIMetaFile&)rMtf).Play(pVDev, rPos, rSize);
707 					((GDIMetaFile&)rMtf).WindStart();
708 
709 					// get content bitmap from buffer
710 					pVDev->EnableMapMode(false);
711 					const Bitmap aPaint(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel()));
712 
713 					// create alpha mask from gradient and get as Bitmap
714 					pVDev->EnableMapMode(bBufferMapModeEnabled);
715 					pVDev->SetDrawMode(DRAWMODE_GRAYGRADIENT);
716 					pVDev->DrawGradient(Rectangle(rPos, rSize), rTransparenceGradient);
717 					pVDev->SetDrawMode(DRAWMODE_DEFAULT);
718 					pVDev->EnableMapMode(false);
719 					const AlphaMask aAlpha(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel()));
720 
721 					// draw masked content to target and restore MapMode
722 					DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
723 					EnableMapMode(bOrigMapModeEnabled);
724 				}
725 				else
726 				{
727 					Bitmap		aPaint, aMask;
728 					AlphaMask	aAlpha;
729 					MapMode 	aMap( GetMapMode() );
730 					Point		aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
731 					const sal_Bool	bOldMap = mbMap;
732 
733 					aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
734 					pVDev->SetMapMode( aMap );
735 					const sal_Bool	bVDevOldMap = pVDev->IsMapModeEnabled();
736 
737 					// create paint bitmap
738 					( (GDIMetaFile&) rMtf ).WindStart();
739 					( (GDIMetaFile&) rMtf ).Play( pVDev, rPos, rSize );
740 					( (GDIMetaFile&) rMtf ).WindStart();
741 					pVDev->EnableMapMode( sal_False );
742 					aPaint = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
743 					pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
744 
745 					// create mask bitmap
746 					pVDev->SetLineColor( COL_BLACK );
747 					pVDev->SetFillColor( COL_BLACK );
748 					pVDev->DrawRect( Rectangle( pVDev->PixelToLogic( Point() ), pVDev->GetOutputSize() ) );
749 					pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT |
750 										DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT );
751 					( (GDIMetaFile&) rMtf ).WindStart();
752 					( (GDIMetaFile&) rMtf ).Play( pVDev, rPos, rSize );
753 					( (GDIMetaFile&) rMtf ).WindStart();
754 					pVDev->EnableMapMode( sal_False );
755 					aMask = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
756 					pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
757 
758 					// create alpha mask from gradient
759 					pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT );
760 					pVDev->DrawGradient( Rectangle( rPos, rSize ), rTransparenceGradient );
761 					pVDev->SetDrawMode( DRAWMODE_DEFAULT );
762 					pVDev->EnableMapMode( sal_False );
763 					pVDev->DrawMask( Point(), pVDev->GetOutputSizePixel(), aMask, Color( COL_WHITE ) );
764 
765 					aAlpha = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
766 
767 					delete pVDev;
768 
769 					EnableMapMode( sal_False );
770 					DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) );
771 					EnableMapMode( bOldMap );
772 				}
773 			}
774 			else
775 				delete pVDev;
776 		}
777 
778 		mpMetaFile = pOldMetaFile;
779 	}
780 }
781 
782 // -----------------------------------------------------------------------
783 
784 void OutputDevice::ImplDrawColorWallpaper( long nX, long nY,
785 										   long nWidth, long nHeight,
786 										   const Wallpaper& rWallpaper )
787 {
788 	// Wallpaper ohne Umrandung zeichnen
789 	Color aOldLineColor = GetLineColor();
790 	Color aOldFillColor = GetFillColor();
791 	SetLineColor();
792 	SetFillColor( rWallpaper.GetColor() );
793     sal_Bool bMap = mbMap;
794     EnableMapMode( sal_False );
795     DrawRect( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
796 	SetLineColor( aOldLineColor );
797 	SetFillColor( aOldFillColor );
798     EnableMapMode( bMap );
799 }
800 
801 // -----------------------------------------------------------------------
802 
803 void OutputDevice::ImplDrawBitmapWallpaper( long nX, long nY,
804 											long nWidth, long nHeight,
805 											const Wallpaper& rWallpaper )
806 {
807 	BitmapEx				aBmpEx;
808 	const BitmapEx* 		pCached = rWallpaper.ImplGetImpWallpaper()->ImplGetCachedBitmap();
809 	Point					aPos;
810 	Size					aSize;
811 	GDIMetaFile*			pOldMetaFile = mpMetaFile;
812 	const WallpaperStyle	eStyle = rWallpaper.GetStyle();
813 	const sal_Bool				bOldMap = mbMap;
814 	sal_Bool					bDrawn = sal_False;
815 	sal_Bool					bDrawGradientBackground = sal_False;
816 	sal_Bool					bDrawColorBackground = sal_False;
817 
818 	if( pCached )
819 		aBmpEx = *pCached;
820 	else
821 		aBmpEx = rWallpaper.GetBitmap();
822 
823 	const long nBmpWidth = aBmpEx.GetSizePixel().Width();
824 	const long nBmpHeight = aBmpEx.GetSizePixel().Height();
825 	const sal_Bool bTransparent = aBmpEx.IsTransparent();
826 
827 	// draw background
828 	if( bTransparent )
829 	{
830 		if( rWallpaper.IsGradient() )
831 			bDrawGradientBackground = sal_True;
832 		else
833 		{
834 			if( !pCached && !rWallpaper.GetColor().GetTransparency() )
835 			{
836 				VirtualDevice aVDev( *this );
837 				aVDev.SetBackground( rWallpaper.GetColor() );
838 				aVDev.SetOutputSizePixel( Size( nBmpWidth, nBmpHeight ) );
839 				aVDev.DrawBitmapEx( Point(), aBmpEx );
840 				aBmpEx = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
841 			}
842 
843 			bDrawColorBackground = sal_True;
844 		}
845 	}
846 	else if( eStyle != WALLPAPER_TILE && eStyle != WALLPAPER_SCALE )
847 	{
848 		if( rWallpaper.IsGradient() )
849 			bDrawGradientBackground = sal_True;
850 		else
851 			bDrawColorBackground = sal_True;
852 	}
853 
854 	// background of bitmap?
855 	if( bDrawGradientBackground )
856 		ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
857 	else if( bDrawColorBackground && bTransparent )
858 	{
859 		ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
860 		bDrawColorBackground = sal_False;
861 	}
862 
863 	// calc pos and size
864 	if( rWallpaper.IsRect() )
865 	{
866 		const Rectangle aBound( LogicToPixel( rWallpaper.GetRect() ) );
867 		aPos = aBound.TopLeft();
868 		aSize = aBound.GetSize();
869 	}
870 	else
871 	{
872 		aPos = Point( nX, nY );
873 		aSize = Size( nWidth, nHeight );
874 	}
875 
876 	mpMetaFile = NULL;
877 	EnableMapMode( sal_False );
878 	Push( PUSH_CLIPREGION );
879 	IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
880 
881 	switch( eStyle )
882 	{
883 		case( WALLPAPER_SCALE ):
884 		{
885 			if( !pCached || ( pCached->GetSizePixel() != aSize ) )
886 			{
887 				if( pCached )
888 					rWallpaper.ImplGetImpWallpaper()->ImplReleaseCachedBitmap();
889 
890 				aBmpEx = rWallpaper.GetBitmap();
891 				aBmpEx.Scale( aSize );
892 				aBmpEx = BitmapEx( aBmpEx.GetBitmap().CreateDisplayBitmap( this ), aBmpEx.GetMask() );
893 			}
894 		}
895 		break;
896 
897 		case( WALLPAPER_TOPLEFT ):
898 		break;
899 
900 		case( WALLPAPER_TOP ):
901 			aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
902 		break;
903 
904 		case( WALLPAPER_TOPRIGHT ):
905 			aPos.X() += ( aSize.Width() - nBmpWidth );
906 		break;
907 
908 		case( WALLPAPER_LEFT ):
909 			aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
910 		break;
911 
912 		case( WALLPAPER_CENTER ):
913 		{
914 			aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
915 			aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
916 		}
917 		break;
918 
919 		case( WALLPAPER_RIGHT ):
920 		{
921 			aPos.X() += ( aSize.Width() - nBmpWidth );
922 			aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
923 		}
924 		break;
925 
926 		case( WALLPAPER_BOTTOMLEFT ):
927 			aPos.Y() += ( aSize.Height() - nBmpHeight );
928 		break;
929 
930 		case( WALLPAPER_BOTTOM ):
931 		{
932 			aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
933 			aPos.Y() += ( aSize.Height() - nBmpHeight );
934 		}
935 		break;
936 
937 		case( WALLPAPER_BOTTOMRIGHT ):
938 		{
939 			aPos.X() += ( aSize.Width() - nBmpWidth );
940 			aPos.Y() += ( aSize.Height() - nBmpHeight );
941 		}
942 		break;
943 
944 		default:
945 		{
946 			const long	nRight = nX + nWidth - 1L;
947 			const long	nBottom = nY + nHeight - 1L;
948 			long		nFirstX;
949 			long		nFirstY;
950 
951 			if( eStyle == WALLPAPER_TILE )
952 			{
953 				nFirstX = aPos.X();
954 				nFirstY = aPos.Y();
955 			}
956 			else
957 			{
958 				nFirstX = aPos.X() + ( ( aSize.Width() - nBmpWidth ) >> 1 );
959 				nFirstY = aPos.Y() + ( ( aSize.Height() - nBmpHeight ) >> 1 );
960 			}
961 
962 			const long	nOffX = ( nFirstX - nX ) % nBmpWidth;
963 			const long	nOffY = ( nFirstY - nY ) % nBmpHeight;
964 			long		nStartX = nX + nOffX;
965 			long		nStartY = nY + nOffY;
966 
967 			if( nOffX > 0L )
968 				nStartX -= nBmpWidth;
969 
970 			if( nOffY > 0L )
971 				nStartY -= nBmpHeight;
972 
973 			for( long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += nBmpHeight )
974 				for( long nBmpX = nStartX; nBmpX <= nRight; nBmpX += nBmpWidth )
975 					DrawBitmapEx( Point( nBmpX, nBmpY ), aBmpEx );
976 
977 			bDrawn = sal_True;
978 		}
979 		break;
980 	}
981 
982 	if( !bDrawn )
983 	{
984 		// optimized for non-transparent bitmaps
985 		if( bDrawColorBackground )
986 		{
987 			const Size		aBmpSize( aBmpEx.GetSizePixel() );
988 			const Point 	aTmpPoint;
989 			const Rectangle aOutRect( aTmpPoint, GetOutputSizePixel() );
990 			const Rectangle aColRect( Point( nX, nY ), Size( nWidth, nHeight ) );
991 			Rectangle		aWorkRect;
992 
993 			aWorkRect = Rectangle( 0, 0, aOutRect.Right(), aPos.Y() - 1L );
994 			aWorkRect.Justify();
995 			aWorkRect.Intersection( aColRect );
996 			if( !aWorkRect.IsEmpty() )
997 			{
998 				ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
999 										aWorkRect.GetWidth(), aWorkRect.GetHeight(),
1000 										rWallpaper );
1001 			}
1002 
1003 			aWorkRect = Rectangle( 0, aPos.Y(), aPos.X() - 1L, aPos.Y() + aBmpSize.Height() - 1L );
1004 			aWorkRect.Justify();
1005 			aWorkRect.Intersection( aColRect );
1006 			if( !aWorkRect.IsEmpty() )
1007 			{
1008 				ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
1009 										aWorkRect.GetWidth(), aWorkRect.GetHeight(),
1010 										rWallpaper );
1011 			}
1012 
1013 			aWorkRect = Rectangle( aPos.X() + aBmpSize.Width(), aPos.Y(), aOutRect.Right(), aPos.Y() + aBmpSize.Height() - 1L );
1014 			aWorkRect.Justify();
1015 			aWorkRect.Intersection( aColRect );
1016 			if( !aWorkRect.IsEmpty() )
1017 			{
1018 				ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
1019 										aWorkRect.GetWidth(), aWorkRect.GetHeight(),
1020 										rWallpaper );
1021 			}
1022 
1023 			aWorkRect = Rectangle( 0, aPos.Y() + aBmpSize.Height(), aOutRect.Right(), aOutRect.Bottom() );
1024 			aWorkRect.Justify();
1025 			aWorkRect.Intersection( aColRect );
1026 			if( !aWorkRect.IsEmpty() )
1027 			{
1028 				ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
1029 										aWorkRect.GetWidth(), aWorkRect.GetHeight(),
1030 										rWallpaper );
1031 			}
1032 		}
1033 
1034 		DrawBitmapEx( aPos, aBmpEx );
1035 	}
1036 
1037 	rWallpaper.ImplGetImpWallpaper()->ImplSetCachedBitmap( aBmpEx );
1038 
1039 	Pop();
1040 	EnableMapMode( bOldMap );
1041 	mpMetaFile = pOldMetaFile;
1042 }
1043 
1044 // -----------------------------------------------------------------------
1045 
1046 void OutputDevice::ImplDrawGradientWallpaper( long nX, long nY,
1047 											  long nWidth, long nHeight,
1048 											  const Wallpaper& rWallpaper )
1049 {
1050 	Rectangle		aBound;
1051 	GDIMetaFile*	pOldMetaFile = mpMetaFile;
1052 	const sal_Bool		bOldMap = mbMap;
1053     sal_Bool            bNeedGradient = sal_True;
1054 
1055 /*
1056 	if ( rWallpaper.IsRect() )
1057 		aBound = LogicToPixel( rWallpaper.GetRect() );
1058 	else
1059 */
1060 		aBound = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
1061 
1062 	mpMetaFile = NULL;
1063 	EnableMapMode( sal_False );
1064 	Push( PUSH_CLIPREGION );
1065 	IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
1066 
1067     if( OUTDEV_WINDOW == meOutDevType && rWallpaper.GetStyle() == WALLPAPER_APPLICATIONGRADIENT )
1068     {
1069         Window *pWin = dynamic_cast< Window* >( this );
1070         if( pWin )
1071         {
1072             // limit gradient to useful size, so that it still can be noticed
1073             // in maximized windows
1074             long gradientWidth = pWin->GetDesktopRectPixel().GetSize().Width();
1075             if( gradientWidth > 1024 )
1076                 gradientWidth = 1024;
1077             if( mnOutOffX+nWidth > gradientWidth )
1078 		        ImplDrawColorWallpaper(  nX, nY, nWidth, nHeight, rWallpaper.GetGradient().GetEndColor() );
1079             if( mnOutOffX > gradientWidth )
1080                 bNeedGradient = sal_False;
1081             else
1082                 aBound = Rectangle( Point( -mnOutOffX, nY ), Size( gradientWidth, nHeight ) );
1083         }
1084     }
1085 
1086     if( bNeedGradient )
1087 	    DrawGradient( aBound, rWallpaper.GetGradient() );
1088 
1089 	Pop();
1090 	EnableMapMode( bOldMap );
1091 	mpMetaFile = pOldMetaFile;
1092 }
1093 
1094 // -----------------------------------------------------------------------
1095 
1096 void OutputDevice::ImplDrawWallpaper( long nX, long nY,
1097 									  long nWidth, long nHeight,
1098 									  const Wallpaper& rWallpaper )
1099 {
1100 	if( rWallpaper.IsBitmap() )
1101 		ImplDrawBitmapWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
1102 	else if( rWallpaper.IsGradient() )
1103 		ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
1104 	else
1105 		ImplDrawColorWallpaper(  nX, nY, nWidth, nHeight, rWallpaper );
1106 }
1107 
1108 // -----------------------------------------------------------------------
1109 
1110 void OutputDevice::DrawWallpaper( const Rectangle& rRect,
1111 								  const Wallpaper& rWallpaper )
1112 {
1113 	if ( mpMetaFile )
1114 		mpMetaFile->AddAction( new MetaWallpaperAction( rRect, rWallpaper ) );
1115 
1116 	if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1117 		return;
1118 
1119 	if ( rWallpaper.GetStyle() != WALLPAPER_NULL )
1120 	{
1121 		Rectangle aRect = LogicToPixel( rRect );
1122 		aRect.Justify();
1123 
1124 		if ( !aRect.IsEmpty() )
1125 		{
1126 			ImplDrawWallpaper( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
1127 							   rWallpaper );
1128 		}
1129 	}
1130 
1131     if( mpAlphaVDev )
1132         mpAlphaVDev->DrawWallpaper( rRect, rWallpaper );
1133 }
1134 
1135 // -----------------------------------------------------------------------
1136 
1137 void OutputDevice::Erase()
1138 {
1139 	if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1140 		return;
1141 
1142     sal_Bool bNativeOK = sal_False;
1143 
1144     if( meOutDevType == OUTDEV_WINDOW )
1145     {
1146         Window* pWindow = static_cast<Window*>(this);
1147         ControlPart aCtrlPart = pWindow->ImplGetWindowImpl()->mnNativeBackground;
1148         if( aCtrlPart != 0 && ! pWindow->IsControlBackground() )
1149         {
1150             ImplControlValue    aControlValue;
1151             Point               aGcc3WorkaroundTemporary;
1152             Rectangle           aCtrlRegion( aGcc3WorkaroundTemporary, GetOutputSizePixel() );
1153             ControlState        nState = 0;
1154 
1155             if( pWindow->IsEnabled() ) 				nState |= CTRL_STATE_ENABLED;
1156             bNativeOK = pWindow->DrawNativeControl( CTRL_WINDOW_BACKGROUND, aCtrlPart, aCtrlRegion,
1157                                                     nState, aControlValue, rtl::OUString() );
1158         }
1159     }
1160 
1161 	if ( mbBackground && ! bNativeOK )
1162 	{
1163 		RasterOp eRasterOp = GetRasterOp();
1164 		if ( eRasterOp != ROP_OVERPAINT )
1165 			SetRasterOp( ROP_OVERPAINT );
1166 		ImplDrawWallpaper( 0, 0, mnOutWidth, mnOutHeight, maBackground );
1167 		if ( eRasterOp != ROP_OVERPAINT )
1168 			SetRasterOp( eRasterOp );
1169 	}
1170 
1171     if( mpAlphaVDev )
1172         mpAlphaVDev->Erase();
1173 }
1174 
1175 // -----------------------------------------------------------------------
1176 
1177 void OutputDevice::ImplDraw2ColorFrame( const Rectangle& rRect,
1178 										const Color& rLeftTopColor,
1179 										const Color& rRightBottomColor )
1180 {
1181 	SetFillColor( rLeftTopColor );
1182 	DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Left(), rRect.Bottom()-1 ) ) );
1183 	DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Right()-1, rRect.Top() ) ) );
1184 	SetFillColor( rRightBottomColor );
1185 	DrawRect( Rectangle( rRect.BottomLeft(), rRect.BottomRight() ) );
1186 	DrawRect( Rectangle( rRect.TopRight(), rRect.BottomRight() ) );
1187 }
1188 
1189 // -----------------------------------------------------------------------
1190 
1191 bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize,
1192 							const GfxLink& rGfxLink, GDIMetaFile* pSubst )
1193 {
1194 	DBG_TRACE( "OutputDevice::DrawEPS()" );
1195 
1196 	bool bDrawn(true);
1197 
1198     if ( mpMetaFile )
1199 	{
1200 		GDIMetaFile aSubst;
1201 
1202 		if( pSubst )
1203 			aSubst = *pSubst;
1204 
1205 		mpMetaFile->AddAction( new MetaEPSAction( rPoint, rSize, rGfxLink, aSubst ) );
1206 	}
1207 
1208 	if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1209 		return bDrawn;
1210 
1211 	if( mbOutputClipped )
1212 		return bDrawn;
1213 
1214 	Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) );
1215 
1216     if( !aRect.IsEmpty() )
1217 	{
1218         // draw the real EPS graphics
1219         if( rGfxLink.GetData() && rGfxLink.GetDataSize() )
1220         {
1221             if( !mpGraphics && !ImplGetGraphics() )
1222                 return bDrawn;
1223 
1224             if( mbInitClipRegion )
1225                 ImplInitClipRegion();
1226 
1227             aRect.Justify();
1228             bDrawn = mpGraphics->DrawEPS( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
1229                          (sal_uInt8*) rGfxLink.GetData(), rGfxLink.GetDataSize(), this );
1230         }
1231 
1232         // else draw the substitution graphics
1233 		if( !bDrawn && pSubst )
1234 		{
1235 			GDIMetaFile* pOldMetaFile = mpMetaFile;
1236 
1237             mpMetaFile = NULL;
1238 			Graphic( *pSubst ).Draw( this, rPoint, rSize );
1239 			mpMetaFile = pOldMetaFile;
1240 		}
1241 	}
1242 
1243     if( mpAlphaVDev )
1244         mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst );
1245 
1246     return bDrawn;
1247 }
1248 
1249 // ------------------------------------------------------------------
1250 
1251 void OutputDevice::DrawRenderGraphic( const Point& rPoint, const Size& rSize,
1252                                       const ::vcl::RenderGraphic& rRenderGraphic )
1253 {
1254 	DBG_TRACE( "OutputDevice::DrawRenderGraphic()" );
1255 
1256 	if( mpMetaFile )
1257 		mpMetaFile->AddAction( new MetaRenderGraphicAction( rPoint, rSize, rRenderGraphic ) );
1258 
1259     if( !rRenderGraphic.IsEmpty() )
1260     {
1261         ::vcl::RenderGraphicRasterizer  aRasterizer( rRenderGraphic );
1262         BitmapEx                        aBmpEx;
1263         const Size                      aSizePixel( LogicToPixel( rSize ) );
1264         GDIMetaFile*                    pOldMetaFile = mpMetaFile;
1265 
1266         mpMetaFile = NULL;
1267         DrawBitmapEx( rPoint, rSize, aRasterizer.Rasterize( aSizePixel ) );
1268         mpMetaFile = pOldMetaFile;
1269     }
1270 }
1271