1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: outdev6.cxx,v $
10 * $Revision: 1.33.16.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
37 #include <vcl/salgdi.hxx>
38 #include <tools/debug.hxx>
39 #include <vcl/outdev.h>
40 #include <vcl/outdev.hxx>
41 #include <vcl/virdev.hxx>
42 #include <vcl/bmpacc.hxx>
43 #include <vcl/metaact.hxx>
44 #include <vcl/gdimtf.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/wrkwin.hxx>
47 #include <vcl/graph.hxx>
48 #include <vcl/wall2.hxx>
49 #include <com/sun/star/uno/Sequence.hxx>
51 #include <basegfx/vector/b2dvector.hxx>
52 #include <basegfx/polygon/b2dpolypolygon.hxx>
53 #include <basegfx/polygon/b2dpolygon.hxx>
54 #include <basegfx/matrix/b2dhommatrix.hxx>
56 #include <vcl/window.h>
57 #include <vcl/svdata.hxx>
59 // ========================================================================
61 DBG_NAMEEX( OutputDevice
)
63 // ------------------------------------------------------------------------
65 void OutputDevice::DrawGrid( const Rectangle
& rRect
, const Size
& rDist
, ULONG nFlags
)
67 DBG_TRACE( "OutputDevice::DrawGrid()" );
68 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
70 Rectangle
aDstRect( PixelToLogic( Point() ), GetOutputSize() );
71 aDstRect
.Intersection( rRect
);
73 if( aDstRect
.IsEmpty() || ImplIsRecordLayout() )
76 if( !mpGraphics
&& !ImplGetGraphics() )
79 if( mbInitClipRegion
)
85 const long nDistX
= Max( rDist
.Width(), 1L );
86 const long nDistY
= Max( rDist
.Height(), 1L );
87 long nX
= ( rRect
.Left() >= aDstRect
.Left() ) ? rRect
.Left() : ( rRect
.Left() + ( ( aDstRect
.Left() - rRect
.Left() ) / nDistX
) * nDistX
);
88 long nY
= ( rRect
.Top() >= aDstRect
.Top() ) ? rRect
.Top() : ( rRect
.Top() + ( ( aDstRect
.Top() - rRect
.Top() ) / nDistY
) * nDistY
);
89 const long nRight
= aDstRect
.Right();
90 const long nBottom
= aDstRect
.Bottom();
91 const long nStartX
= ImplLogicXToDevicePixel( nX
);
92 const long nEndX
= ImplLogicXToDevicePixel( nRight
);
93 const long nStartY
= ImplLogicYToDevicePixel( nY
);
94 const long nEndY
= ImplLogicYToDevicePixel( nBottom
);
98 ::com::sun::star::uno::Sequence
< sal_Int32
> aVertBuf
;
99 ::com::sun::star::uno::Sequence
< sal_Int32
> aHorzBuf
;
101 if( ( nFlags
& GRID_DOTS
) || ( nFlags
& GRID_HORZLINES
) )
103 aVertBuf
.realloc( aDstRect
.GetHeight() / nDistY
+ 2L );
104 aVertBuf
[ nVertCount
++ ] = nStartY
;
105 while( ( nY
+= nDistY
) <= nBottom
)
106 aVertBuf
[ nVertCount
++ ] = ImplLogicYToDevicePixel( nY
);
109 if( ( nFlags
& GRID_DOTS
) || ( nFlags
& GRID_VERTLINES
) )
111 aHorzBuf
.realloc( aDstRect
.GetWidth() / nDistX
+ 2L );
112 aHorzBuf
[ nHorzCount
++ ] = nStartX
;
113 while( ( nX
+= nDistX
) <= nRight
)
114 aHorzBuf
[ nHorzCount
++ ] = ImplLogicXToDevicePixel( nX
);
117 if( mbInitLineColor
)
120 if( mbInitFillColor
)
123 const BOOL bOldMap
= mbMap
;
124 EnableMapMode( FALSE
);
126 if( nFlags
& GRID_DOTS
)
128 for( long i
= 0L; i
< nVertCount
; i
++ )
129 for( long j
= 0L, Y
= aVertBuf
[ i
]; j
< nHorzCount
; j
++ )
130 mpGraphics
->DrawPixel( aHorzBuf
[ j
], Y
, this );
134 if( nFlags
& GRID_HORZLINES
)
136 for( long i
= 0L; i
< nVertCount
; i
++ )
139 mpGraphics
->DrawLine( nStartX
, nY
, nEndX
, nY
, this );
143 if( nFlags
& GRID_VERTLINES
)
145 for( long i
= 0L; i
< nHorzCount
; i
++ )
148 mpGraphics
->DrawLine( nX
, nStartY
, nX
, nEndY
, this );
153 EnableMapMode( bOldMap
);
156 mpAlphaVDev
->DrawGrid( rRect
, rDist
, nFlags
);
159 // ------------------------------------------------------------------------
160 // Caution: This method is nearly the same as
161 // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
162 // so when changes are made here do not forget to make change sthere, too
164 void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon
& rB2DPolyPoly
, double fTransparency
)
166 DBG_TRACE( "OutputDevice::DrawTransparent(B2D&,transparency)" );
167 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
169 // AW: Do NOT paint empty PolyPolygons
170 if(!rB2DPolyPoly
.count())
173 // we need a graphics
175 if( !ImplGetGraphics() )
178 if( mbInitClipRegion
)
179 ImplInitClipRegion();
180 if( mbOutputClipped
)
183 if( mbInitLineColor
)
185 if( mbInitFillColor
)
188 if((mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
)
189 && mpGraphics
->supportsOperation(OutDevSupport_B2DDraw
)
190 && ROP_OVERPAINT
== GetRasterOp()
193 // b2dpolygon support not implemented yet on non-UNX platforms
194 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
195 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rB2DPolyPoly
);
197 // transform the polygon and ensure closed
198 aB2DPolyPolygon
.transform(aTransform
);
199 aB2DPolyPolygon
.setClosed(true);
201 if(mpGraphics
->DrawPolyPolygon(aB2DPolyPolygon
, fTransparency
, this))
204 // MetaB2DPolyPolygonAction is not implemented yet:
205 // according to AW adding it is very dangerous since there is a lot
206 // of code that uses the metafile actions directly and unless every
207 // place that does this knows about the new action we need to fallback
209 mpMetaFile
->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly
) );
212 mpMetaFile
->AddAction( new MetaTransparentAction( PolyPolygon( rB2DPolyPoly
), static_cast< sal_uInt16
>(fTransparency
* 100.0)));
218 // fallback to old polygon drawing if needed
219 const PolyPolygon
aToolsPolyPolygon( rB2DPolyPoly
);
220 DrawTransparent(PolyPolygon(rB2DPolyPoly
), static_cast< sal_uInt16
>(fTransparency
* 100.0));
223 // ------------------------------------------------------------------------
225 void OutputDevice::DrawTransparent( const PolyPolygon
& rPolyPoly
,
226 USHORT nTransparencePercent
)
228 DBG_TRACE( "OutputDevice::DrawTransparent()" );
229 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
231 // short circuit for drawing an opaque polygon
232 if( (nTransparencePercent
< 1) || ((mnDrawMode
& DRAWMODE_NOTRANSPARENCY
) != 0) )
234 DrawPolyPolygon( rPolyPoly
);
238 // short circut for drawing an invisible polygon
239 if( !mbFillColor
|| (nTransparencePercent
>= 100) )
241 // short circuit if the polygon border is invisible too
245 // DrawTransparent() assumes that the border is NOT to be drawn transparently???
246 Push( PUSH_FILLCOLOR
);
248 DrawPolyPolygon( rPolyPoly
);
253 // handle metafile recording
255 mpMetaFile
->AddAction( new MetaTransparentAction( rPolyPoly
, nTransparencePercent
) );
257 bool bDrawn
= !IsDeviceOutputNecessary() || ImplIsRecordLayout();
261 // get the device graphics as drawing target
263 if( !ImplGetGraphics() )
267 static const char* pDisableNative
= getenv( "SAL_DISABLE_NATIVE_ALPHA");
269 // try hard to draw it directly, because the emulation layers are slower
271 && mpGraphics
->supportsOperation( OutDevSupport_B2DDraw
)
273 // workaround bad dithering on remote displaying when using GDI+ with toolbar buttoin hilighting
274 && !rPolyPoly
.IsRect()
278 // prepare the graphics device
279 if( mbInitClipRegion
)
280 ImplInitClipRegion();
281 if( mbOutputClipped
)
283 if( mbInitLineColor
)
285 if( mbInitFillColor
)
288 // get the polygon in device coordinates
289 basegfx::B2DPolyPolygon
aB2DPolyPolygon( rPolyPoly
.getB2DPolyPolygon() );
290 aB2DPolyPolygon
.setClosed( true );
291 const ::basegfx::B2DHomMatrix aTransform
= ImplGetDeviceTransformation();
292 aB2DPolyPolygon
.transform( aTransform
);
294 // draw the transparent polygon
295 bDrawn
= mpGraphics
->DrawPolyPolygon( aB2DPolyPolygon
, nTransparencePercent
*0.01, this );
297 // DrawTransparent() assumes that the border is NOT to be drawn transparently???
300 // disable the fill color for now
301 mpGraphics
->SetFillColor();
302 // draw the border line
303 const basegfx::B2DVector
aLineWidths( 1, 1 );
304 const int nPolyCount
= aB2DPolyPolygon
.count();
305 for( int nPolyIdx
= 0; nPolyIdx
< nPolyCount
; ++nPolyIdx
)
307 const ::basegfx::B2DPolygon
& rPolygon
= aB2DPolyPolygon
.getB2DPolygon( nPolyIdx
);
308 mpGraphics
->DrawPolyLine( rPolygon
, aLineWidths
, ::basegfx::B2DLINEJOIN_NONE
, this );
310 // prepare to restore the fill color
311 mbInitFillColor
= mbFillColor
;
320 VirtualDevice
* pOldAlphaVDev
= mpAlphaVDev
;
322 // #110958# Disable alpha VDev, we perform the necessary
323 // operation explicitely further below.
327 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
330 if( OUTDEV_PRINTER
== meOutDevType
)
332 Rectangle
aPolyRect( LogicToPixel( rPolyPoly
).GetBoundRect() );
333 const Size
aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH
) );
334 const long nBaseExtent
= Max( FRound( aDPISize
.Width() / 300. ), 1L );
336 const USHORT nTrans
= ( nTransparencePercent
< 13 ) ? 0 :
337 ( nTransparencePercent
< 38 ) ? 25 :
338 ( nTransparencePercent
< 63 ) ? 50 :
339 ( nTransparencePercent
< 88 ) ? 75 : 100;
343 case( 25 ): nMove
= nBaseExtent
* 3; break;
344 case( 50 ): nMove
= nBaseExtent
* 4; break;
345 case( 75 ): nMove
= nBaseExtent
* 6; break;
346 // TODO What is the correct VALUE???
347 default: nMove
= 0; break;
350 Push( PUSH_CLIPREGION
| PUSH_LINECOLOR
);
351 IntersectClipRegion( rPolyPoly
);
352 SetLineColor( GetFillColor() );
354 Rectangle
aRect( aPolyRect
.TopLeft(), Size( aPolyRect
.GetWidth(), nBaseExtent
) );
356 const BOOL bOldMap
= mbMap
;
357 EnableMapMode( FALSE
);
359 while( aRect
.Top() <= aPolyRect
.Bottom() )
362 aRect
.Move( 0, nMove
);
365 aRect
= Rectangle( aPolyRect
.TopLeft(), Size( nBaseExtent
, aPolyRect
.GetHeight() ) );
366 while( aRect
.Left() <= aPolyRect
.Right() )
369 aRect
.Move( nMove
, 0 );
372 EnableMapMode( bOldMap
);
377 PolyPolygon
aPolyPoly( LogicToPixel( rPolyPoly
) );
378 Rectangle
aPolyRect( aPolyPoly
.GetBoundRect() );
380 Rectangle
aDstRect( aPoint
, GetOutputSizePixel() );
382 aDstRect
.Intersection( aPolyRect
);
384 if( OUTDEV_WINDOW
== meOutDevType
)
386 const Region
aPaintRgn( ( (Window
*) this )->GetPaintRegion() );
388 if( !aPaintRgn
.IsNull() )
389 aDstRect
.Intersection( LogicToPixel( aPaintRgn
).GetBoundRect() );
392 if( !aDstRect
.IsEmpty() )
394 // #i66849# Added fast path for exactly rectangular
396 // #i83087# Naturally, system alpha blending cannot
397 // work with separate alpha VDev
398 if( !mpAlphaVDev
&& !pDisableNative
&& aPolyPoly
.IsRect() )
400 // setup Graphics only here (other cases delegate
401 // to basic OutDev methods)
404 if ( mbInitClipRegion
)
405 ImplInitClipRegion();
406 if ( mbInitLineColor
)
408 if ( mbInitFillColor
)
411 Rectangle
aLogicPolyRect( rPolyPoly
.GetBoundRect() );
412 Rectangle
aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect
) );
414 if( !mbOutputClipped
)
416 bDrawn
= mpGraphics
->DrawAlphaRect(
417 aPixelRect
.Left(), aPixelRect
.Top(),
418 // #i98405# use methods with small g, else one pixel too much will be painted.
419 // This is because the source is a polygon which when painted would not paint
420 // the rightmost and lowest pixel line(s), so use one pixel less for the
422 aPixelRect
.getWidth(), aPixelRect
.getHeight(),
423 sal::static_int_cast
<sal_uInt8
>(nTransparencePercent
),
433 VirtualDevice
aVDev( *this, 1 );
434 const Size
aDstSz( aDstRect
.GetSize() );
435 const BYTE cTrans
= (BYTE
) MinMax( FRound( nTransparencePercent
* 2.55 ), 0, 255 );
437 if( aDstRect
.Left() || aDstRect
.Top() )
438 aPolyPoly
.Move( -aDstRect
.Left(), -aDstRect
.Top() );
440 if( aVDev
.SetOutputSizePixel( aDstSz
) )
442 const BOOL bOldMap
= mbMap
;
444 EnableMapMode( FALSE
);
446 aVDev
.SetLineColor( COL_BLACK
);
447 aVDev
.SetFillColor( COL_BLACK
);
448 aVDev
.DrawPolyPolygon( aPolyPoly
);
450 Bitmap
aPaint( GetBitmap( aDstRect
.TopLeft(), aDstSz
) );
451 Bitmap
aPolyMask( aVDev
.GetBitmap( Point(), aDstSz
) );
453 // #107766# check for non-empty bitmaps before accessing them
454 if( !!aPaint
&& !!aPolyMask
)
456 BitmapWriteAccess
* pW
= aPaint
.AcquireWriteAccess();
457 BitmapReadAccess
* pR
= aPolyMask
.AcquireReadAccess();
462 const BitmapColor
aFillCol( GetFillColor() );
463 const BitmapColor
aWhite( pR
->GetBestMatchingColor( Color( COL_WHITE
) ) );
464 const BitmapColor
aBlack( pR
->GetBestMatchingColor( Color( COL_BLACK
) ) );
465 const long nWidth
= pW
->Width(), nHeight
= pW
->Height();
466 const long nR
= aFillCol
.GetRed(), nG
= aFillCol
.GetGreen(), nB
= aFillCol
.GetBlue();
469 if( aPaint
.GetBitCount() <= 8 )
471 const BitmapPalette
& rPal
= pW
->GetPalette();
472 const USHORT nCount
= rPal
.GetEntryCount();
473 BitmapColor
* pMap
= (BitmapColor
*) new BYTE
[ nCount
* sizeof( BitmapColor
) ];
475 for( USHORT i
= 0; i
< nCount
; i
++ )
477 BitmapColor
aCol( rPal
[ i
] );
478 pMap
[ i
] = BitmapColor( (BYTE
) rPal
.GetBestIndex( aCol
.Merge( aFillCol
, cTrans
) ) );
481 if( pR
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
&&
482 pW
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
484 const BYTE cBlack
= aBlack
.GetIndex();
486 for( nY
= 0; nY
< nHeight
; nY
++ )
488 Scanline pWScan
= pW
->GetScanline( nY
);
489 Scanline pRScan
= pR
->GetScanline( nY
);
492 for( nX
= 0; nX
< nWidth
; nX
++, cBit
>>= 1, pWScan
++ )
495 cBit
= 128, pRScan
++;
497 if( ( *pRScan
& cBit
) == cBlack
)
498 *pWScan
= (BYTE
) pMap
[ *pWScan
].GetIndex();
504 for( nY
= 0; nY
< nHeight
; nY
++ )
505 for( nX
= 0; nX
< nWidth
; nX
++ )
506 if( pR
->GetPixel( nY
, nX
) == aBlack
)
507 pW
->SetPixel( nY
, nX
, pMap
[ pW
->GetPixel( nY
, nX
).GetIndex() ] );
510 delete[] (BYTE
*) pMap
;
514 if( pR
->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL
&&
515 pW
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR
)
517 const BYTE cBlack
= aBlack
.GetIndex();
519 for( nY
= 0; nY
< nHeight
; nY
++ )
521 Scanline pWScan
= pW
->GetScanline( nY
);
522 Scanline pRScan
= pR
->GetScanline( nY
);
525 for( nX
= 0; nX
< nWidth
; nX
++, cBit
>>= 1, pWScan
+= 3 )
528 cBit
= 128, pRScan
++;
530 if( ( *pRScan
& cBit
) == cBlack
)
532 pWScan
[ 0 ] = COLOR_CHANNEL_MERGE( pWScan
[ 0 ], nB
, cTrans
);
533 pWScan
[ 1 ] = COLOR_CHANNEL_MERGE( pWScan
[ 1 ], nG
, cTrans
);
534 pWScan
[ 2 ] = COLOR_CHANNEL_MERGE( pWScan
[ 2 ], nR
, cTrans
);
541 for( nY
= 0; nY
< nHeight
; nY
++ )
543 for( nX
= 0; nX
< nWidth
; nX
++ )
545 if( pR
->GetPixel( nY
, nX
) == aBlack
)
547 aPixCol
= pW
->GetColor( nY
, nX
);
548 pW
->SetPixel( nY
, nX
, aPixCol
.Merge( aFillCol
, cTrans
) );
556 aPolyMask
.ReleaseAccess( pR
);
557 aPaint
.ReleaseAccess( pW
);
559 DrawBitmap( aDstRect
.TopLeft(), aPaint
);
561 EnableMapMode( bOldMap
);
565 Push( PUSH_FILLCOLOR
);
567 DrawPolyPolygon( rPolyPoly
);
573 DrawPolyPolygon( rPolyPoly
);
578 mpMetaFile
= pOldMetaFile
;
580 // #110958# Restore disabled alpha VDev
581 mpAlphaVDev
= pOldAlphaVDev
;
583 // #110958# Apply alpha value also to VDev alpha channel
586 const Color
aFillCol( mpAlphaVDev
->GetFillColor() );
587 mpAlphaVDev
->SetFillColor( Color(sal::static_int_cast
<UINT8
>(255*nTransparencePercent
/100),
588 sal::static_int_cast
<UINT8
>(255*nTransparencePercent
/100),
589 sal::static_int_cast
<UINT8
>(255*nTransparencePercent
/100)) );
591 mpAlphaVDev
->DrawTransparent( rPolyPoly
, nTransparencePercent
);
593 mpAlphaVDev
->SetFillColor( aFillCol
);
598 // -----------------------------------------------------------------------
600 void OutputDevice::DrawTransparent( const GDIMetaFile
& rMtf
, const Point
& rPos
,
601 const Size
& rSize
, const Gradient
& rTransparenceGradient
)
603 DBG_TRACE( "OutputDevice::DrawTransparent()" );
604 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
606 const Color
aBlack( COL_BLACK
);
609 mpMetaFile
->AddAction( new MetaFloatTransparentAction( rMtf
, rPos
, rSize
, rTransparenceGradient
) );
611 if( ( rTransparenceGradient
.GetStartColor() == aBlack
&& rTransparenceGradient
.GetEndColor() == aBlack
) ||
612 ( mnDrawMode
& ( DRAWMODE_NOTRANSPARENCY
) ) )
614 ( (GDIMetaFile
&) rMtf
).WindStart();
615 ( (GDIMetaFile
&) rMtf
).Play( this, rPos
, rSize
);
616 ( (GDIMetaFile
&) rMtf
).WindStart();
620 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
621 Rectangle
aOutRect( LogicToPixel( rPos
), LogicToPixel( rSize
) );
623 Rectangle
aDstRect( aPoint
, GetOutputSizePixel() );
626 aDstRect
.Intersection( aOutRect
);
628 if( OUTDEV_WINDOW
== meOutDevType
)
630 const Region
aPaintRgn( ( (Window
*) this )->GetPaintRegion() );
632 if( !aPaintRgn
.IsNull() )
633 aDstRect
.Intersection( LogicToPixel( aPaintRgn
.GetBoundRect() ) );
636 if( !aDstRect
.IsEmpty() )
638 VirtualDevice
* pVDev
= new VirtualDevice
;
640 ((OutputDevice
*)pVDev
)->mnDPIX
= mnDPIX
;
641 ((OutputDevice
*)pVDev
)->mnDPIY
= mnDPIY
;
643 if( pVDev
->SetOutputSizePixel( aDstRect
.GetSize() ) )
645 if(GetAntialiasing())
648 // For MetaFile replay (see task) it may now be neccessary to take
649 // into account that the content is AntiAlialised and needs to be masked
650 // like that. Instead of masking, i will use a copy-modify-paste cycle
651 // here (as i already use in the VclPrimiziveRenderer with successs)
652 pVDev
->SetAntialiasing(GetAntialiasing());
654 // create MapMode for buffer (offset needed) and set
655 MapMode
aMap(GetMapMode());
656 const Point
aOutPos(PixelToLogic(aDstRect
.TopLeft()));
657 aMap
.SetOrigin(Point(-aOutPos
.X(), -aOutPos
.Y()));
658 pVDev
->SetMapMode(aMap
);
660 // copy MapMode state and disable for target
661 const bool bOrigMapModeEnabled(IsMapModeEnabled());
662 EnableMapMode(false);
664 // copy MapMode state and disable for buffer
665 const bool bBufferMapModeEnabled(pVDev
->IsMapModeEnabled());
666 pVDev
->EnableMapMode(false);
668 // copy content from original to buffer
670 aPoint
, pVDev
->GetOutputSizePixel(), // dest
671 aDstRect
.TopLeft(), pVDev
->GetOutputSizePixel(), // source
674 // draw MetaFile to buffer
675 pVDev
->EnableMapMode(bBufferMapModeEnabled
);
676 ((GDIMetaFile
&)rMtf
).WindStart();
677 ((GDIMetaFile
&)rMtf
).Play(pVDev
, rPos
, rSize
);
678 ((GDIMetaFile
&)rMtf
).WindStart();
680 // get content bitmap from buffer
681 pVDev
->EnableMapMode(false);
682 const Bitmap
aPaint(pVDev
->GetBitmap(aPoint
, pVDev
->GetOutputSizePixel()));
684 // create alpha mask from gradient and get as Bitmap
685 pVDev
->EnableMapMode(bBufferMapModeEnabled
);
686 pVDev
->SetDrawMode(DRAWMODE_GRAYGRADIENT
);
687 pVDev
->DrawGradient(Rectangle(rPos
, rSize
), rTransparenceGradient
);
688 pVDev
->SetDrawMode(DRAWMODE_DEFAULT
);
689 pVDev
->EnableMapMode(false);
690 const AlphaMask
aAlpha(pVDev
->GetBitmap(aPoint
, pVDev
->GetOutputSizePixel()));
692 // draw masked content to target and restore MapMode
693 DrawBitmapEx(aDstRect
.TopLeft(), BitmapEx(aPaint
, aAlpha
));
694 EnableMapMode(bOrigMapModeEnabled
);
698 Bitmap aPaint
, aMask
;
700 MapMode
aMap( GetMapMode() );
701 Point
aOutPos( PixelToLogic( aDstRect
.TopLeft() ) );
702 const BOOL bOldMap
= mbMap
;
704 aMap
.SetOrigin( Point( -aOutPos
.X(), -aOutPos
.Y() ) );
705 pVDev
->SetMapMode( aMap
);
706 const BOOL bVDevOldMap
= pVDev
->IsMapModeEnabled();
708 // create paint bitmap
709 ( (GDIMetaFile
&) rMtf
).WindStart();
710 ( (GDIMetaFile
&) rMtf
).Play( pVDev
, rPos
, rSize
);
711 ( (GDIMetaFile
&) rMtf
).WindStart();
712 pVDev
->EnableMapMode( FALSE
);
713 aPaint
= pVDev
->GetBitmap( Point(), pVDev
->GetOutputSizePixel() );
714 pVDev
->EnableMapMode( bVDevOldMap
); // #i35331#: MUST NOT use EnableMapMode( TRUE ) here!
716 // create mask bitmap
717 pVDev
->SetLineColor( COL_BLACK
);
718 pVDev
->SetFillColor( COL_BLACK
);
719 pVDev
->DrawRect( Rectangle( pVDev
->PixelToLogic( Point() ), pVDev
->GetOutputSize() ) );
720 pVDev
->SetDrawMode( DRAWMODE_WHITELINE
| DRAWMODE_WHITEFILL
| DRAWMODE_WHITETEXT
|
721 DRAWMODE_WHITEBITMAP
| DRAWMODE_WHITEGRADIENT
);
722 ( (GDIMetaFile
&) rMtf
).WindStart();
723 ( (GDIMetaFile
&) rMtf
).Play( pVDev
, rPos
, rSize
);
724 ( (GDIMetaFile
&) rMtf
).WindStart();
725 pVDev
->EnableMapMode( FALSE
);
726 aMask
= pVDev
->GetBitmap( Point(), pVDev
->GetOutputSizePixel() );
727 pVDev
->EnableMapMode( bVDevOldMap
); // #i35331#: MUST NOT use EnableMapMode( TRUE ) here!
729 // create alpha mask from gradient
730 pVDev
->SetDrawMode( DRAWMODE_GRAYGRADIENT
);
731 pVDev
->DrawGradient( Rectangle( rPos
, rSize
), rTransparenceGradient
);
732 pVDev
->SetDrawMode( DRAWMODE_DEFAULT
);
733 pVDev
->EnableMapMode( FALSE
);
734 pVDev
->DrawMask( Point(), pVDev
->GetOutputSizePixel(), aMask
, Color( COL_WHITE
) );
736 aAlpha
= pVDev
->GetBitmap( Point(), pVDev
->GetOutputSizePixel() );
740 EnableMapMode( FALSE
);
741 DrawBitmapEx( aDstRect
.TopLeft(), BitmapEx( aPaint
, aAlpha
) );
742 EnableMapMode( bOldMap
);
749 mpMetaFile
= pOldMetaFile
;
753 // -----------------------------------------------------------------------
755 void OutputDevice::ImplDrawColorWallpaper( long nX
, long nY
,
756 long nWidth
, long nHeight
,
757 const Wallpaper
& rWallpaper
)
759 // Wallpaper ohne Umrandung zeichnen
760 Color aOldLineColor
= GetLineColor();
761 Color aOldFillColor
= GetFillColor();
763 SetFillColor( rWallpaper
.GetColor() );
765 EnableMapMode( FALSE
);
766 DrawRect( Rectangle( Point( nX
, nY
), Size( nWidth
, nHeight
) ) );
767 SetLineColor( aOldLineColor
);
768 SetFillColor( aOldFillColor
);
769 EnableMapMode( bMap
);
772 // -----------------------------------------------------------------------
774 void OutputDevice::ImplDrawBitmapWallpaper( long nX
, long nY
,
775 long nWidth
, long nHeight
,
776 const Wallpaper
& rWallpaper
)
779 const BitmapEx
* pCached
= rWallpaper
.ImplGetImpWallpaper()->ImplGetCachedBitmap();
782 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
783 const WallpaperStyle eStyle
= rWallpaper
.GetStyle();
784 const BOOL bOldMap
= mbMap
;
786 BOOL bDrawGradientBackground
= FALSE
;
787 BOOL bDrawColorBackground
= FALSE
;
792 aBmpEx
= rWallpaper
.GetBitmap();
794 const long nBmpWidth
= aBmpEx
.GetSizePixel().Width();
795 const long nBmpHeight
= aBmpEx
.GetSizePixel().Height();
796 const BOOL bTransparent
= aBmpEx
.IsTransparent();
801 if( rWallpaper
.IsGradient() )
802 bDrawGradientBackground
= TRUE
;
805 if( !pCached
&& !rWallpaper
.GetColor().GetTransparency() )
807 VirtualDevice
aVDev( *this );
808 aVDev
.SetBackground( rWallpaper
.GetColor() );
809 aVDev
.SetOutputSizePixel( Size( nBmpWidth
, nBmpHeight
) );
810 aVDev
.DrawBitmapEx( Point(), aBmpEx
);
811 aBmpEx
= aVDev
.GetBitmap( Point(), aVDev
.GetOutputSizePixel() );
814 bDrawColorBackground
= TRUE
;
817 else if( eStyle
!= WALLPAPER_TILE
&& eStyle
!= WALLPAPER_SCALE
)
819 if( rWallpaper
.IsGradient() )
820 bDrawGradientBackground
= TRUE
;
822 bDrawColorBackground
= TRUE
;
825 // background of bitmap?
826 if( bDrawGradientBackground
)
827 ImplDrawGradientWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
);
828 else if( bDrawColorBackground
&& bTransparent
)
830 ImplDrawColorWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
);
831 bDrawColorBackground
= FALSE
;
835 if( rWallpaper
.IsRect() )
837 const Rectangle
aBound( LogicToPixel( rWallpaper
.GetRect() ) );
838 aPos
= aBound
.TopLeft();
839 aSize
= aBound
.GetSize();
843 aPos
= Point( nX
, nY
);
844 aSize
= Size( nWidth
, nHeight
);
848 EnableMapMode( FALSE
);
849 Push( PUSH_CLIPREGION
);
850 IntersectClipRegion( Rectangle( Point( nX
, nY
), Size( nWidth
, nHeight
) ) );
854 case( WALLPAPER_SCALE
):
856 if( !pCached
|| ( pCached
->GetSizePixel() != aSize
) )
859 rWallpaper
.ImplGetImpWallpaper()->ImplReleaseCachedBitmap();
861 aBmpEx
= rWallpaper
.GetBitmap();
862 aBmpEx
.Scale( aSize
);
863 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap().CreateDisplayBitmap( this ), aBmpEx
.GetMask() );
868 case( WALLPAPER_TOPLEFT
):
871 case( WALLPAPER_TOP
):
872 aPos
.X() += ( aSize
.Width() - nBmpWidth
) >> 1;
875 case( WALLPAPER_TOPRIGHT
):
876 aPos
.X() += ( aSize
.Width() - nBmpWidth
);
879 case( WALLPAPER_LEFT
):
880 aPos
.Y() += ( aSize
.Height() - nBmpHeight
) >> 1;
883 case( WALLPAPER_CENTER
):
885 aPos
.X() += ( aSize
.Width() - nBmpWidth
) >> 1;
886 aPos
.Y() += ( aSize
.Height() - nBmpHeight
) >> 1;
890 case( WALLPAPER_RIGHT
):
892 aPos
.X() += ( aSize
.Width() - nBmpWidth
);
893 aPos
.Y() += ( aSize
.Height() - nBmpHeight
) >> 1;
897 case( WALLPAPER_BOTTOMLEFT
):
898 aPos
.Y() += ( aSize
.Height() - nBmpHeight
);
901 case( WALLPAPER_BOTTOM
):
903 aPos
.X() += ( aSize
.Width() - nBmpWidth
) >> 1;
904 aPos
.Y() += ( aSize
.Height() - nBmpHeight
);
908 case( WALLPAPER_BOTTOMRIGHT
):
910 aPos
.X() += ( aSize
.Width() - nBmpWidth
);
911 aPos
.Y() += ( aSize
.Height() - nBmpHeight
);
917 const long nRight
= nX
+ nWidth
- 1L;
918 const long nBottom
= nY
+ nHeight
- 1L;
922 if( eStyle
== WALLPAPER_TILE
)
929 nFirstX
= aPos
.X() + ( ( aSize
.Width() - nBmpWidth
) >> 1 );
930 nFirstY
= aPos
.Y() + ( ( aSize
.Height() - nBmpHeight
) >> 1 );
933 const long nOffX
= ( nFirstX
- nX
) % nBmpWidth
;
934 const long nOffY
= ( nFirstY
- nY
) % nBmpHeight
;
935 long nStartX
= nX
+ nOffX
;
936 long nStartY
= nY
+ nOffY
;
939 nStartX
-= nBmpWidth
;
942 nStartY
-= nBmpHeight
;
944 for( long nBmpY
= nStartY
; nBmpY
<= nBottom
; nBmpY
+= nBmpHeight
)
945 for( long nBmpX
= nStartX
; nBmpX
<= nRight
; nBmpX
+= nBmpWidth
)
946 DrawBitmapEx( Point( nBmpX
, nBmpY
), aBmpEx
);
955 // optimized for non-transparent bitmaps
956 if( bDrawColorBackground
)
958 const Size
aBmpSize( aBmpEx
.GetSizePixel() );
959 const Point aTmpPoint
;
960 const Rectangle
aOutRect( aTmpPoint
, GetOutputSizePixel() );
961 const Rectangle
aColRect( Point( nX
, nY
), Size( nWidth
, nHeight
) );
964 aWorkRect
= Rectangle( 0, 0, aOutRect
.Right(), aPos
.Y() - 1L );
966 aWorkRect
.Intersection( aColRect
);
967 if( !aWorkRect
.IsEmpty() )
969 ImplDrawColorWallpaper( aWorkRect
.Left(), aWorkRect
.Top(),
970 aWorkRect
.GetWidth(), aWorkRect
.GetHeight(),
974 aWorkRect
= Rectangle( 0, aPos
.Y(), aPos
.X() - 1L, aPos
.Y() + aBmpSize
.Height() - 1L );
976 aWorkRect
.Intersection( aColRect
);
977 if( !aWorkRect
.IsEmpty() )
979 ImplDrawColorWallpaper( aWorkRect
.Left(), aWorkRect
.Top(),
980 aWorkRect
.GetWidth(), aWorkRect
.GetHeight(),
984 aWorkRect
= Rectangle( aPos
.X() + aBmpSize
.Width(), aPos
.Y(), aOutRect
.Right(), aPos
.Y() + aBmpSize
.Height() - 1L );
986 aWorkRect
.Intersection( aColRect
);
987 if( !aWorkRect
.IsEmpty() )
989 ImplDrawColorWallpaper( aWorkRect
.Left(), aWorkRect
.Top(),
990 aWorkRect
.GetWidth(), aWorkRect
.GetHeight(),
994 aWorkRect
= Rectangle( 0, aPos
.Y() + aBmpSize
.Height(), aOutRect
.Right(), aOutRect
.Bottom() );
996 aWorkRect
.Intersection( aColRect
);
997 if( !aWorkRect
.IsEmpty() )
999 ImplDrawColorWallpaper( aWorkRect
.Left(), aWorkRect
.Top(),
1000 aWorkRect
.GetWidth(), aWorkRect
.GetHeight(),
1005 DrawBitmapEx( aPos
, aBmpEx
);
1008 rWallpaper
.ImplGetImpWallpaper()->ImplSetCachedBitmap( aBmpEx
);
1011 EnableMapMode( bOldMap
);
1012 mpMetaFile
= pOldMetaFile
;
1015 // -----------------------------------------------------------------------
1017 void OutputDevice::ImplDrawGradientWallpaper( long nX
, long nY
,
1018 long nWidth
, long nHeight
,
1019 const Wallpaper
& rWallpaper
)
1022 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
1023 const BOOL bOldMap
= mbMap
;
1024 BOOL bNeedGradient
= TRUE
;
1027 if ( rWallpaper.IsRect() )
1028 aBound = LogicToPixel( rWallpaper.GetRect() );
1031 aBound
= Rectangle( Point( nX
, nY
), Size( nWidth
, nHeight
) );
1034 EnableMapMode( FALSE
);
1035 Push( PUSH_CLIPREGION
);
1036 IntersectClipRegion( Rectangle( Point( nX
, nY
), Size( nWidth
, nHeight
) ) );
1038 if( OUTDEV_WINDOW
== meOutDevType
&& rWallpaper
.GetStyle() == WALLPAPER_APPLICATIONGRADIENT
)
1040 Window
*pWin
= dynamic_cast< Window
* >( this );
1043 // limit gradient to useful size, so that it still can be noticed
1044 // in maximized windows
1045 long gradientWidth
= pWin
->GetDesktopRectPixel().GetSize().Width();
1046 if( gradientWidth
> 1024 )
1047 gradientWidth
= 1024;
1048 if( mnOutOffX
+nWidth
> gradientWidth
)
1049 ImplDrawColorWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
.GetGradient().GetEndColor() );
1050 if( mnOutOffX
> gradientWidth
)
1051 bNeedGradient
= FALSE
;
1053 aBound
= Rectangle( Point( -mnOutOffX
, nY
), Size( gradientWidth
, nHeight
) );
1058 DrawGradient( aBound
, rWallpaper
.GetGradient() );
1061 EnableMapMode( bOldMap
);
1062 mpMetaFile
= pOldMetaFile
;
1065 // -----------------------------------------------------------------------
1067 void OutputDevice::ImplDrawWallpaper( long nX
, long nY
,
1068 long nWidth
, long nHeight
,
1069 const Wallpaper
& rWallpaper
)
1071 if( rWallpaper
.IsBitmap() )
1072 ImplDrawBitmapWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
);
1073 else if( rWallpaper
.IsGradient() )
1074 ImplDrawGradientWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
);
1076 ImplDrawColorWallpaper( nX
, nY
, nWidth
, nHeight
, rWallpaper
);
1079 // -----------------------------------------------------------------------
1081 void OutputDevice::DrawWallpaper( const Rectangle
& rRect
,
1082 const Wallpaper
& rWallpaper
)
1085 mpMetaFile
->AddAction( new MetaWallpaperAction( rRect
, rWallpaper
) );
1087 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1090 if ( rWallpaper
.GetStyle() != WALLPAPER_NULL
)
1092 Rectangle aRect
= LogicToPixel( rRect
);
1095 if ( !aRect
.IsEmpty() )
1097 ImplDrawWallpaper( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight(),
1103 mpAlphaVDev
->DrawWallpaper( rRect
, rWallpaper
);
1106 // -----------------------------------------------------------------------
1108 void OutputDevice::Erase()
1110 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1113 BOOL bNativeOK
= FALSE
;
1114 if( meOutDevType
== OUTDEV_WINDOW
)
1116 Window
* pWindow
= static_cast<Window
*>(this);
1117 ControlPart aCtrlPart
= pWindow
->ImplGetWindowImpl()->mnNativeBackground
;
1118 if( aCtrlPart
!= 0 && ! pWindow
->IsControlBackground() )
1120 ImplControlValue aControlValue
;
1121 Point aGcc3WorkaroundTemporary
;
1122 Region
aCtrlRegion( Rectangle( aGcc3WorkaroundTemporary
, GetOutputSizePixel() ) );
1123 ControlState nState
= 0;
1125 if( pWindow
->IsEnabled() ) nState
|= CTRL_STATE_ENABLED
;
1126 bNativeOK
= pWindow
->DrawNativeControl( CTRL_WINDOW_BACKGROUND
, aCtrlPart
, aCtrlRegion
,
1127 nState
, aControlValue
, rtl::OUString() );
1131 if ( mbBackground
&& ! bNativeOK
)
1133 RasterOp eRasterOp
= GetRasterOp();
1134 if ( eRasterOp
!= ROP_OVERPAINT
)
1135 SetRasterOp( ROP_OVERPAINT
);
1136 ImplDrawWallpaper( 0, 0, mnOutWidth
, mnOutHeight
, maBackground
);
1137 if ( eRasterOp
!= ROP_OVERPAINT
)
1138 SetRasterOp( eRasterOp
);
1142 mpAlphaVDev
->Erase();
1145 // -----------------------------------------------------------------------
1147 void OutputDevice::ImplDraw2ColorFrame( const Rectangle
& rRect
,
1148 const Color
& rLeftTopColor
,
1149 const Color
& rRightBottomColor
)
1151 SetFillColor( rLeftTopColor
);
1152 DrawRect( Rectangle( rRect
.TopLeft(), Point( rRect
.Left(), rRect
.Bottom()-1 ) ) );
1153 DrawRect( Rectangle( rRect
.TopLeft(), Point( rRect
.Right()-1, rRect
.Top() ) ) );
1154 SetFillColor( rRightBottomColor
);
1155 DrawRect( Rectangle( rRect
.BottomLeft(), rRect
.BottomRight() ) );
1156 DrawRect( Rectangle( rRect
.TopRight(), rRect
.BottomRight() ) );
1159 // -----------------------------------------------------------------------
1161 void OutputDevice::DrawEPS( const Point
& rPoint
, const Size
& rSize
,
1162 const GfxLink
& rGfxLink
, GDIMetaFile
* pSubst
)
1171 mpMetaFile
->AddAction( new MetaEPSAction( rPoint
, rSize
, rGfxLink
, aSubst
) );
1174 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1177 if( mbOutputClipped
)
1180 Rectangle
aRect( ImplLogicToDevicePixel( Rectangle( rPoint
, rSize
) ) );
1181 if( !aRect
.IsEmpty() )
1183 // draw the real EPS graphics
1184 bool bDrawn
= FALSE
;
1185 if( rGfxLink
.GetData() && rGfxLink
.GetDataSize() )
1187 if( !mpGraphics
&& !ImplGetGraphics() )
1190 if( mbInitClipRegion
)
1191 ImplInitClipRegion();
1194 bDrawn
= mpGraphics
->DrawEPS( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight(),
1195 (BYTE
*) rGfxLink
.GetData(), rGfxLink
.GetDataSize(), this );
1198 // else draw the substitution graphics
1199 if( !bDrawn
&& pSubst
)
1201 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
1204 Graphic( *pSubst
).Draw( this, rPoint
, rSize
);
1205 mpMetaFile
= pOldMetaFile
;
1210 mpAlphaVDev
->DrawEPS( rPoint
, rSize
, rGfxLink
, pSubst
);