1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "gdiimpl.hxx"
26 #include <rtl/strbuf.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/poly.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <basegfx/polygon/b2dpolygontools.hxx>
31 #include <basegfx/polygon/b2dpolypolygontools.hxx>
32 #include <win/wincomp.hxx>
33 #include <win/saldata.hxx>
34 #include <win/salgdi.h>
35 #include "win/salbmp.h"
36 #include <vcl/salbtype.hxx>
37 #include <win/salframe.h>
38 #include <basegfx/matrix/b2dhommatrixtools.hxx>
40 #include "outdata.hxx"
41 #include "win/salids.hrc"
45 #define min(a,b) (((a) < (b)) ? (a) : (b))
48 #define max(a,b) (((a) > (b)) ? (a) : (b))
53 #pragma warning(push, 1)
63 #include <gdiplusenums.h>
64 #include <gdipluscolor.h>
70 #include <basegfx/polygon/b2dpolygon.hxx>
72 #define SAL_POLYPOLYCOUNT_STACKBUF 8
73 #define SAL_POLYPOLYPOINTS_STACKBUF 64
75 #define DITHER_PAL_DELTA 51
76 #define DITHER_PAL_STEPS 6
77 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
78 #define DITHER_MAX_SYSCOLOR 16
79 #define DITHER_EXTRA_COLORS 1
80 #define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
82 #define SAL_POLY_STACKBUF 32
83 #define USE_GDI_BEZIERS
87 // #100127# draw an array of points which might also contain bezier control points
88 void ImplRenderPath( HDC hdc
, sal_uLong nPoints
, const SalPoint
* pPtAry
, const BYTE
* pFlgAry
)
93 // TODO: profile whether the following options are faster:
94 // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
95 // b) convert our flag array to window's and use PolyDraw
97 MoveToEx( hdc
, pPtAry
->mnX
, pPtAry
->mnY
, NULL
);
100 for( i
=1; i
<nPoints
; ++i
, ++pPtAry
, ++pFlgAry
)
102 if( *pFlgAry
!= POLY_CONTROL
)
104 LineTo( hdc
, pPtAry
->mnX
, pPtAry
->mnY
);
106 else if( nPoints
- i
> 2 )
108 PolyBezierTo( hdc
, reinterpret_cast<const POINT
*>(pPtAry
), 3 );
109 i
+= 2; pPtAry
+= 2; pFlgAry
+= 2;
115 // #100127# Fill point and flag memory from array of points which
116 // might also contain bezier control points for the PolyDraw() GDI method
117 // Make sure pWinPointAry and pWinFlagAry are big enough
118 void ImplPreparePolyDraw( bool bCloseFigures
,
120 const sal_uInt32
* pPoints
,
121 const SalPoint
* const* pPtAry
,
122 const BYTE
* const* pFlgAry
,
127 for( nCurrPoly
=0; nCurrPoly
<nPoly
; ++nCurrPoly
)
129 const POINT
* pCurrPoint
= reinterpret_cast<const POINT
*>( *pPtAry
++ );
130 const BYTE
* pCurrFlag
= *pFlgAry
++;
131 const sal_uInt32 nCurrPoints
= *pPoints
++;
132 const bool bHaveFlagArray( pCurrFlag
);
133 sal_uLong nCurrPoint
;
138 *pWinPointAry
++ = *pCurrPoint
++;
139 *pWinFlagAry
++ = PT_MOVETO
;
142 for( nCurrPoint
=1; nCurrPoint
<nCurrPoints
; )
144 // #102067# Check existence of flag array
145 if( bHaveFlagArray
&&
146 ( nCurrPoint
+ 2 ) < nCurrPoints
)
148 BYTE
P4( pCurrFlag
[ 2 ] );
150 if( ( POLY_CONTROL
== pCurrFlag
[ 0 ] ) &&
151 ( POLY_CONTROL
== pCurrFlag
[ 1 ] ) &&
152 ( POLY_NORMAL
== P4
|| POLY_SMOOTH
== P4
|| POLY_SYMMTR
== P4
) )
155 *pWinPointAry
++ = *pCurrPoint
++;
156 *pWinFlagAry
++ = PT_BEZIERTO
;
159 *pWinPointAry
++ = *pCurrPoint
++;
160 *pWinFlagAry
++ = PT_BEZIERTO
;
163 *pWinPointAry
++ = *pCurrPoint
++;
164 *pWinFlagAry
++ = PT_BEZIERTO
;
172 // regular line point
173 *pWinPointAry
++ = *pCurrPoint
++;
174 *pWinFlagAry
++ = PT_LINETO
;
181 pWinFlagAry
[-1] |= PT_CLOSEFIGURE
;
187 static PALETTEENTRY aImplSalSysPalEntryAry
[ DITHER_MAX_SYSCOLOR
] =
192 { 0, 0x80, 0x80, 0 },
194 { 0x80, 0, 0x80, 0 },
195 { 0x80, 0x80, 0, 0 },
196 { 0x80, 0x80, 0x80, 0 },
197 { 0xC0, 0xC0, 0xC0, 0 },
200 { 0, 0xFF, 0xFF, 0 },
202 { 0xFF, 0, 0xFF, 0 },
203 { 0xFF, 0xFF, 0, 0 },
204 { 0xFF, 0xFF, 0xFF, 0 }
207 static PALETTEENTRY aImplExtraColor1
=
212 static BYTE aOrdDither8Bit
[8][8] =
214 { 0, 38, 9, 48, 2, 40, 12, 50 },
215 { 25, 12, 35, 22, 28, 15, 37, 24 },
216 { 6, 44, 3, 41, 8, 47, 5, 44 },
217 { 32, 19, 28, 16, 34, 21, 31, 18 },
218 { 1, 40, 11, 49, 0, 39, 10, 48 },
219 { 27, 14, 36, 24, 26, 13, 36, 23 },
220 { 8, 46, 4, 43, 7, 45, 4, 42 },
221 { 33, 20, 30, 17, 32, 20, 29, 16 }
224 static BYTE aOrdDither16Bit
[8][8] =
226 { 0, 6, 1, 7, 0, 6, 1, 7 },
227 { 4, 2, 5, 3, 4, 2, 5, 3 },
228 { 1, 7, 0, 6, 1, 7, 0, 6 },
229 { 5, 3, 4, 2, 5, 3, 4, 2 },
230 { 0, 6, 1, 7, 0, 6, 1, 7 },
231 { 4, 2, 5, 3, 4, 2, 5, 3 },
232 { 1, 7, 0, 6, 1, 7, 0, 6 },
233 { 5, 3, 4, 2, 5, 3, 4, 2 }
236 SalColor
ImplGetROPSalColor( SalROPColor nROPColor
)
239 if ( nROPColor
== SAL_ROP_0
)
240 nSalColor
= MAKE_SALCOLOR( 0, 0, 0 );
242 nSalColor
= MAKE_SALCOLOR( 255, 255, 255 );
246 int ImplIsPaletteEntry( BYTE nRed
, BYTE nGreen
, BYTE nBlue
)
249 if ( !(nRed
% DITHER_PAL_DELTA
) && !(nGreen
% DITHER_PAL_DELTA
) && !(nBlue
% DITHER_PAL_DELTA
) )
252 PALETTEENTRY
* pPalEntry
= aImplSalSysPalEntryAry
;
254 // standard palette color?
255 for ( sal_uInt16 i
= 0; i
< DITHER_MAX_SYSCOLOR
; i
++, pPalEntry
++ )
257 if( pPalEntry
->peRed
== nRed
&& pPalEntry
->peGreen
== nGreen
&& pPalEntry
->peBlue
== nBlue
)
262 if ( aImplExtraColor1
.peRed
== nRed
&&
263 aImplExtraColor1
.peGreen
== nGreen
&&
264 aImplExtraColor1
.peBlue
== nBlue
)
274 WinSalGraphicsImpl::WinSalGraphicsImpl(WinSalGraphics
& rParent
):
282 WinSalGraphicsImpl::~WinSalGraphicsImpl()
293 DeleteBrush( mhBrush
);
298 void WinSalGraphicsImpl::Init()
302 void WinSalGraphicsImpl::freeResources()
306 bool WinSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uLong
)
311 void WinSalGraphicsImpl::copyBits( const SalTwoRect
& rPosAry
, SalGraphics
* pSrcGraphics
)
317 hSrcDC
= static_cast<WinSalGraphics
*>(pSrcGraphics
)->getHDC();
319 hSrcDC
= mrParent
.getHDC();
326 if ( (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
327 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
) )
329 BitBlt( mrParent
.getHDC(),
330 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
331 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
333 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
338 int nOldStretchMode
= SetStretchBltMode( mrParent
.getHDC(), STRETCH_DELETESCANS
);
339 StretchBlt( mrParent
.getHDC(),
340 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
341 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
343 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
344 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
346 SetStretchBltMode( mrParent
.getHDC(), nOldStretchMode
);
350 void ImplCalcOutSideRgn( const RECT
& rSrcRect
,
351 int nLeft
, int nTop
, int nRight
, int nBottom
,
352 HRGN
& rhInvalidateRgn
)
356 // calculate area outside the visible region
357 if ( rSrcRect
.left
< nLeft
)
359 if ( !rhInvalidateRgn
)
360 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
361 hTempRgn
= CreateRectRgn( -31999, 0, nLeft
, 31999 );
362 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
363 DeleteRegion( hTempRgn
);
365 if ( rSrcRect
.top
< nTop
)
367 if ( !rhInvalidateRgn
)
368 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
369 hTempRgn
= CreateRectRgn( 0, -31999, 31999, nTop
);
370 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
371 DeleteRegion( hTempRgn
);
373 if ( rSrcRect
.right
> nRight
)
375 if ( !rhInvalidateRgn
)
376 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
377 hTempRgn
= CreateRectRgn( nRight
, 0, 31999, 31999 );
378 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
379 DeleteRegion( hTempRgn
);
381 if ( rSrcRect
.bottom
> nBottom
)
383 if ( !rhInvalidateRgn
)
384 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
385 hTempRgn
= CreateRectRgn( 0, nBottom
, 31999, 31999 );
386 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
387 DeleteRegion( hTempRgn
);
391 void WinSalGraphicsImpl::copyArea( long nDestX
, long nDestY
,
392 long nSrcX
, long nSrcY
,
393 long nSrcWidth
, long nSrcHeight
,
396 bool bRestoreClipRgn
= false;
397 HRGN hOldClipRgn
= 0;
398 int nOldClipRgnType
= ERROR
;
399 HRGN hInvalidateRgn
= 0;
401 // do we have to invalidate also the overlapping regions?
402 if ( (nFlags
& SAL_COPYAREA_WINDOWINVALIDATE
) && mrParent
.isWindow() )
404 // compute and invalidate those parts that were either off-screen or covered by other windows
405 // while performing the above BitBlt
406 // those regions then have to be invalidated as they contain useless/wrong data
414 // restrict srcRect to this window (calc intersection)
415 aSrcRect
.left
= (int)nSrcX
;
416 aSrcRect
.top
= (int)nSrcY
;
417 aSrcRect
.right
= aSrcRect
.left
+(int)nSrcWidth
;
418 aSrcRect
.bottom
= aSrcRect
.top
+(int)nSrcHeight
;
419 GetClientRect( mrParent
.gethWnd(), &aClipRect
);
420 if ( IntersectRect( &aSrcRect
, &aSrcRect
, &aClipRect
) )
422 // transform srcRect to screen coordinates
426 ClientToScreen( mrParent
.gethWnd(), &aPt
);
427 aSrcRect
.left
+= aPt
.x
;
428 aSrcRect
.top
+= aPt
.y
;
429 aSrcRect
.right
+= aPt
.x
;
430 aSrcRect
.bottom
+= aPt
.y
;
433 // compute the parts that are off screen (ie invisible)
435 ImplSalGetWorkArea( NULL
, &theScreen
, NULL
); // find the screen area taking multiple monitors into account
436 ImplCalcOutSideRgn( aSrcRect
, theScreen
.left
, theScreen
.top
, theScreen
.right
, theScreen
.bottom
, hInvalidateRgn
);
438 // calculate regions that are covered by other windows
440 HWND hWndTopWindow
= mrParent
.gethWnd();
441 // Find the TopLevel Window, because only Windows which are in
442 // in the foreground of our TopLevel window must be considered
443 if ( GetWindowStyle( hWndTopWindow
) & WS_CHILD
)
445 RECT aTempRect3
= aSrcRect
;
448 hWndTopWindow
= ::GetParent( hWndTopWindow
);
450 // Test if the Parent clips our window
451 GetClientRect( hWndTopWindow
, &aTempRect
);
455 ClientToScreen( hWndTopWindow
, &aPt2
);
456 aTempRect
.left
+= aPt2
.x
;
457 aTempRect
.top
+= aPt2
.y
;
458 aTempRect
.right
+= aPt2
.x
;
459 aTempRect
.bottom
+= aPt2
.y
;
460 IntersectRect( &aTempRect3
, &aTempRect3
, &aTempRect
);
462 while ( GetWindowStyle( hWndTopWindow
) & WS_CHILD
);
464 // If one or more Parents clip our window, than we must
465 // calculate the outside area
466 if ( !EqualRect( &aSrcRect
, &aTempRect3
) )
468 ImplCalcOutSideRgn( aSrcRect
,
469 aTempRect3
.left
, aTempRect3
.top
,
470 aTempRect3
.right
, aTempRect3
.bottom
,
474 // retrieve the top-most (z-order) child window
475 hWnd
= GetWindow( GetDesktopWindow(), GW_CHILD
);
478 if ( hWnd
== hWndTopWindow
)
480 if ( IsWindowVisible( hWnd
) && !IsIconic( hWnd
) )
482 GetWindowRect( hWnd
, &aTempRect
);
483 if ( IntersectRect( &aTempRect2
, &aSrcRect
, &aTempRect
) )
485 // hWnd covers part or all of aSrcRect
486 if ( !hInvalidateRgn
)
487 hInvalidateRgn
= CreateRectRgnIndirect( &aSrcRect
);
489 // get full bounding box of hWnd
490 hTempRgn
= CreateRectRgnIndirect( &aTempRect
);
492 // get region of hWnd (the window may be shaped)
494 hTempRgn2
= CreateRectRgn( 0, 0, 0, 0 );
495 int nRgnType
= GetWindowRgn( hWnd
, hTempRgn2
);
496 if ( (nRgnType
!= ERROR
) && (nRgnType
!= NULLREGION
) )
498 // convert window region to screen coordinates
499 OffsetRgn( hTempRgn2
, aTempRect
.left
, aTempRect
.top
);
500 // and intersect with the window's bounding box
501 CombineRgn( hTempRgn
, hTempRgn
, hTempRgn2
, RGN_AND
);
503 // finally compute that part of aSrcRect which is not covered by any parts of hWnd
504 CombineRgn( hInvalidateRgn
, hInvalidateRgn
, hTempRgn
, RGN_DIFF
);
505 DeleteRegion( hTempRgn
);
508 // retrieve the next window in the z-order, i.e. the window below hwnd
509 hWnd
= GetWindow( hWnd
, GW_HWNDNEXT
);
512 DeleteRegion( hTempRgn2
);
513 if ( hInvalidateRgn
)
515 // hInvalidateRgn contains the fully visible parts of the original srcRect
516 hTempRgn
= CreateRectRgnIndirect( &aSrcRect
);
517 // subtract it from the original rect to get the occluded parts
518 int nRgnType
= CombineRgn( hInvalidateRgn
, hTempRgn
, hInvalidateRgn
, RGN_DIFF
);
519 DeleteRegion( hTempRgn
);
521 if ( (nRgnType
!= ERROR
) && (nRgnType
!= NULLREGION
) )
523 // move the occluded parts to the destination pos
524 int nOffX
= (int)(nDestX
-nSrcX
);
525 int nOffY
= (int)(nDestY
-nSrcY
);
526 OffsetRgn( hInvalidateRgn
, nOffX
-aPt
.x
, nOffY
-aPt
.y
);
528 // by excluding hInvalidateRgn from the system's clip region
529 // we will prevent bitblt from copying useless data
530 // epsecially now shadows from overlapping windows will appear (#i36344)
531 hOldClipRgn
= CreateRectRgn( 0, 0, 0, 0 );
532 nOldClipRgnType
= GetClipRgn( mrParent
.getHDC(), hOldClipRgn
);
534 bRestoreClipRgn
= TRUE
; // indicate changed clipregion and force invalidate
535 ExtSelectClipRgn( mrParent
.getHDC(), hInvalidateRgn
, RGN_DIFF
);
541 BitBlt( mrParent
.getHDC(),
542 (int)nDestX
, (int)nDestY
,
543 (int)nSrcWidth
, (int)nSrcHeight
,
545 (int)nSrcX
, (int)nSrcY
,
548 if( bRestoreClipRgn
)
550 // restore old clip region
551 if( nOldClipRgnType
!= ERROR
)
552 SelectClipRgn( mrParent
.getHDC(), hOldClipRgn
);
553 DeleteRegion( hOldClipRgn
);
555 // invalidate regions that were not copied
556 bool bInvalidate
= true;
558 // Combine Invalidate vcl::Region with existing ClipRegion
559 HRGN hTempRgn
= CreateRectRgn( 0, 0, 0, 0 );
560 if ( GetClipRgn( mrParent
.getHDC(), hTempRgn
) == 1 )
562 int nRgnType
= CombineRgn( hInvalidateRgn
, hTempRgn
, hInvalidateRgn
, RGN_AND
);
563 if ( (nRgnType
== ERROR
) || (nRgnType
== NULLREGION
) )
566 DeleteRegion( hTempRgn
);
570 InvalidateRgn( mrParent
.gethWnd(), hInvalidateRgn
, TRUE
);
571 // here we only initiate an update if this is the MainThread,
572 // so that there is no deadlock when handling the Paint event,
573 // as the SolarMutex is already held by this Thread
574 SalData
* pSalData
= GetSalData();
575 DWORD nCurThreadId
= GetCurrentThreadId();
576 if ( pSalData
->mnAppThreadId
== nCurThreadId
)
577 UpdateWindow( mrParent
.gethWnd() );
580 DeleteRegion( hInvalidateRgn
);
587 void ImplDrawBitmap( HDC hDC
, const SalTwoRect
& rPosAry
, const WinSalBitmap
& rSalBitmap
,
588 bool bPrinter
, int nDrawMode
)
593 HBITMAP hDrawDDB
= rSalBitmap
.ImplGethDDB();
594 WinSalBitmap
* pTmpSalBmp
= NULL
;
595 bool bPrintDDB
= ( bPrinter
&& hDrawDDB
);
599 pTmpSalBmp
= new WinSalBitmap
;
600 pTmpSalBmp
->Create( rSalBitmap
, rSalBitmap
.GetBitCount() );
601 hDrawDIB
= pTmpSalBmp
->ImplGethDIB();
604 hDrawDIB
= rSalBitmap
.ImplGethDIB();
608 PBITMAPINFO pBI
= (PBITMAPINFO
) GlobalLock( hDrawDIB
);
609 PBITMAPINFOHEADER pBIH
= (PBITMAPINFOHEADER
) pBI
;
610 PBYTE pBits
= (PBYTE
) pBI
+ *(DWORD
*) pBI
+
611 rSalBitmap
.ImplGetDIBColorCount( hDrawDIB
) * sizeof( RGBQUAD
);
612 const int nOldStretchMode
= SetStretchBltMode( hDC
, STRETCH_DELETESCANS
);
615 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
616 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
617 (int)rPosAry
.mnSrcX
, (int)(pBIH
->biHeight
- rPosAry
.mnSrcHeight
- rPosAry
.mnSrcY
),
618 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
619 pBits
, pBI
, DIB_RGB_COLORS
, nDrawMode
);
621 GlobalUnlock( hDrawDIB
);
622 SetStretchBltMode( hDC
, nOldStretchMode
);
624 else if( hDrawDDB
&& !bPrintDDB
)
626 HDC hBmpDC
= ImplGetCachedDC( CACHED_HDC_DRAW
, hDrawDDB
);
627 COLORREF nOldBkColor
= RGB(0xFF,0xFF,0xFF);
628 COLORREF nOldTextColor
= RGB(0,0,0);
629 bool bMono
= ( rSalBitmap
.GetBitCount() == 1 );
633 COLORREF nBkColor
= RGB( 0xFF, 0xFF, 0xFF );
634 COLORREF nTextColor
= RGB( 0x00, 0x00, 0x00 );
635 //fdo#33455 handle 1 bit depth pngs with palette entries
636 //to set fore/back colors
637 if (BitmapBuffer
* pBitmapBuffer
= const_cast<WinSalBitmap
&>(rSalBitmap
).AcquireBuffer(BITMAP_INFO_ACCESS
))
639 const BitmapPalette
& rPalette
= pBitmapBuffer
->maPalette
;
640 if (rPalette
.GetEntryCount() == 2)
643 nCol
= ImplColorToSal(rPalette
[0]);
644 nTextColor
= RGB( SALCOLOR_RED(nCol
), SALCOLOR_GREEN(nCol
), SALCOLOR_BLUE(nCol
) );
645 nCol
= ImplColorToSal(rPalette
[1]);
646 nBkColor
= RGB( SALCOLOR_RED(nCol
), SALCOLOR_GREEN(nCol
), SALCOLOR_BLUE(nCol
) );
648 const_cast<WinSalBitmap
&>(rSalBitmap
).ReleaseBuffer(pBitmapBuffer
, BITMAP_INFO_ACCESS
);
650 nOldBkColor
= SetBkColor( hDC
, nBkColor
);
651 nOldTextColor
= ::SetTextColor( hDC
, nTextColor
);
654 if ( (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
655 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
) )
658 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
659 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
661 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
666 const int nOldStretchMode
= SetStretchBltMode( hDC
, STRETCH_DELETESCANS
);
669 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
670 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
672 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
673 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
676 SetStretchBltMode( hDC
, nOldStretchMode
);
681 SetBkColor( hDC
, nOldBkColor
);
682 ::SetTextColor( hDC
, nOldTextColor
);
685 ImplReleaseCachedDC( CACHED_HDC_DRAW
);
695 void WinSalGraphicsImpl::drawBitmap(const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
)
697 bool bTryDirectPaint(!mrParent
.isPrinter() && !mbXORMode
);
701 // only paint direct when no scaling and no MapMode, else the
702 // more expensive conversions may be done for short-time Bitmap/BitmapEx
703 // used for buffering only
704 if(rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
&& rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
)
706 bTryDirectPaint
= false;
710 // try to draw using GdiPlus directly
711 if(bTryDirectPaint
&& tryDrawBitmapGdiPlus(rPosAry
, rSalBitmap
))
716 // fall back old stuff
717 ImplDrawBitmap(mrParent
.getHDC(), rPosAry
, static_cast<const WinSalBitmap
&>(rSalBitmap
),
718 mrParent
.isPrinter(),
719 mbXORMode
? SRCINVERT
: SRCCOPY
);
722 void WinSalGraphicsImpl::drawBitmap( const SalTwoRect
& rPosAry
,
723 const SalBitmap
& rSSalBitmap
,
724 SalColor nTransparentColor
)
726 DBG_ASSERT( !mrParent
.isPrinter(), "No transparency print possible!" );
728 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
730 WinSalBitmap
* pMask
= new WinSalBitmap
;
732 const Size
aSize( rSalBitmap
.GetSize() );
733 HBITMAP hMaskBitmap
= CreateBitmap( (int) aSize
.Width(), (int) aSize
.Height(), 1, 1, NULL
);
734 HDC hMaskDC
= ImplGetCachedDC( CACHED_HDC_1
, hMaskBitmap
);
735 const BYTE cRed
= SALCOLOR_RED( nTransparentColor
);
736 const BYTE cGreen
= SALCOLOR_GREEN( nTransparentColor
);
737 const BYTE cBlue
= SALCOLOR_BLUE( nTransparentColor
);
739 if( rSalBitmap
.ImplGethDDB() )
741 HDC hSrcDC
= ImplGetCachedDC( CACHED_HDC_2
, rSalBitmap
.ImplGethDDB() );
742 COLORREF aOldCol
= SetBkColor( hSrcDC
, RGB( cRed
, cGreen
, cBlue
) );
744 BitBlt( hMaskDC
, 0, 0, (int) aSize
.Width(), (int) aSize
.Height(), hSrcDC
, 0, 0, SRCCOPY
);
746 SetBkColor( hSrcDC
, aOldCol
);
747 ImplReleaseCachedDC( CACHED_HDC_2
);
751 WinSalBitmap
* pTmpSalBmp
= new WinSalBitmap
;
753 if( pTmpSalBmp
->Create( rSalBitmap
, &mrParent
) )
755 HDC hSrcDC
= ImplGetCachedDC( CACHED_HDC_2
, pTmpSalBmp
->ImplGethDDB() );
756 COLORREF aOldCol
= SetBkColor( hSrcDC
, RGB( cRed
, cGreen
, cBlue
) );
758 BitBlt( hMaskDC
, 0, 0, (int) aSize
.Width(), (int) aSize
.Height(), hSrcDC
, 0, 0, SRCCOPY
);
760 SetBkColor( hSrcDC
, aOldCol
);
761 ImplReleaseCachedDC( CACHED_HDC_2
);
767 ImplReleaseCachedDC( CACHED_HDC_1
);
769 // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE )
770 if( pMask
->Create( hMaskBitmap
, FALSE
, FALSE
) )
771 drawBitmap( rPosAry
, rSalBitmap
, *pMask
);
776 void WinSalGraphicsImpl::drawBitmap( const SalTwoRect
& rPosAry
,
777 const SalBitmap
& rSSalBitmap
,
778 const SalBitmap
& rSTransparentBitmap
)
780 DBG_ASSERT( !mrParent
.isPrinter(), "No transparency print possible!" );
781 bool bTryDirectPaint(!mrParent
.isPrinter() && !mbXORMode
);
783 // try to draw using GdiPlus directly
784 if(bTryDirectPaint
&& drawAlphaBitmap(rPosAry
, rSSalBitmap
, rSTransparentBitmap
))
789 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
790 const WinSalBitmap
& rTransparentBitmap
= static_cast<const WinSalBitmap
&>(rSTransparentBitmap
);
792 SalTwoRect aPosAry
= rPosAry
;
793 int nDstX
= (int)aPosAry
.mnDestX
;
794 int nDstY
= (int)aPosAry
.mnDestY
;
795 int nDstWidth
= (int)aPosAry
.mnDestWidth
;
796 int nDstHeight
= (int)aPosAry
.mnDestHeight
;
797 HDC hDC
= mrParent
.getHDC();
798 HBITMAP hMemBitmap
= 0;
799 HBITMAP hMaskBitmap
= 0;
801 if( ( nDstWidth
> CACHED_HDC_DEFEXT
) || ( nDstHeight
> CACHED_HDC_DEFEXT
) )
803 hMemBitmap
= CreateCompatibleBitmap( hDC
, nDstWidth
, nDstHeight
);
804 hMaskBitmap
= CreateCompatibleBitmap( hDC
, nDstWidth
, nDstHeight
);
807 HDC hMemDC
= ImplGetCachedDC( CACHED_HDC_1
, hMemBitmap
);
808 HDC hMaskDC
= ImplGetCachedDC( CACHED_HDC_2
, hMaskBitmap
);
810 aPosAry
.mnDestX
= aPosAry
.mnDestY
= 0;
811 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hDC
, nDstX
, nDstY
, SRCCOPY
);
813 // WIN/WNT seems to have a minor problem mapping the correct color of the
814 // mask to the palette if we draw the DIB directly ==> draw DDB
815 if( ( GetBitCount() <= 8 ) && rTransparentBitmap
.ImplGethDIB() && rTransparentBitmap
.GetBitCount() == 1 )
819 if( aTmp
.Create( rTransparentBitmap
, &mrParent
) )
820 ImplDrawBitmap( hMaskDC
, aPosAry
, aTmp
, FALSE
, SRCCOPY
);
823 ImplDrawBitmap( hMaskDC
, aPosAry
, rTransparentBitmap
, FALSE
, SRCCOPY
);
825 // now MemDC contains background, MaskDC the transparency mask
827 // #105055# Respect XOR mode
830 ImplDrawBitmap( hMaskDC
, aPosAry
, rSalBitmap
, FALSE
, SRCERASE
);
831 // now MaskDC contains the bitmap area with black background
832 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCINVERT
);
833 // now MemDC contains background XORed bitmap area ontop
837 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCAND
);
838 // now MemDC contains background with masked-out bitmap area
839 ImplDrawBitmap( hMaskDC
, aPosAry
, rSalBitmap
, FALSE
, SRCERASE
);
840 // now MaskDC contains the bitmap area with black background
841 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCPAINT
);
842 // now MemDC contains background and bitmap merged together
845 BitBlt( hDC
, nDstX
, nDstY
, nDstWidth
, nDstHeight
, hMemDC
, 0, 0, SRCCOPY
);
847 ImplReleaseCachedDC( CACHED_HDC_1
);
848 ImplReleaseCachedDC( CACHED_HDC_2
);
850 // hMemBitmap != 0 ==> hMaskBitmap != 0
853 DeleteObject( hMemBitmap
);
854 DeleteObject( hMaskBitmap
);
858 bool WinSalGraphicsImpl::drawAlphaRect( long nX
, long nY
, long nWidth
,
859 long nHeight
, sal_uInt8 nTransparency
)
861 if( mbPen
|| !mbBrush
|| mbXORMode
)
862 return false; // can only perform solid fills without XOR.
864 HDC hMemDC
= ImplGetCachedDC( CACHED_HDC_1
, 0 );
865 SetPixel( hMemDC
, (int)0, (int)0, mnBrushColor
);
867 BLENDFUNCTION aFunc
= {
870 sal::static_int_cast
<sal_uInt8
>(255 - 255L*nTransparency
/100),
874 // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
876 bool bRet
= AlphaBlend( mrParent
.getHDC(), nX
, nY
, nWidth
, nHeight
,
880 ImplReleaseCachedDC( CACHED_HDC_1
);
885 void WinSalGraphicsImpl::drawMask( const SalTwoRect
& rPosAry
,
886 const SalBitmap
& rSSalBitmap
,
887 SalColor nMaskColor
)
889 DBG_ASSERT( !mrParent
.isPrinter(), "No transparency print possible!" );
891 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
893 SalTwoRect aPosAry
= rPosAry
;
894 const BYTE cRed
= SALCOLOR_RED( nMaskColor
);
895 const BYTE cGreen
= SALCOLOR_GREEN( nMaskColor
);
896 const BYTE cBlue
= SALCOLOR_BLUE( nMaskColor
);
897 HDC hDC
= mrParent
.getHDC();
898 HBRUSH hMaskBrush
= CreateSolidBrush( RGB( cRed
, cGreen
, cBlue
) );
899 HBRUSH hOldBrush
= SelectBrush( hDC
, hMaskBrush
);
901 // WIN/WNT seems to have a minor problem mapping the correct color of the
902 // mask to the palette if we draw the DIB directly ==> draw DDB
903 if( ( GetBitCount() <= 8 ) && rSalBitmap
.ImplGethDIB() && rSalBitmap
.GetBitCount() == 1 )
907 if( aTmp
.Create( rSalBitmap
, &mrParent
) )
908 ImplDrawBitmap( hDC
, aPosAry
, aTmp
, FALSE
, 0x00B8074AUL
);
911 ImplDrawBitmap( hDC
, aPosAry
, rSalBitmap
, FALSE
, 0x00B8074AUL
);
913 SelectBrush( hDC
, hOldBrush
);
914 DeleteBrush( hMaskBrush
);
917 SalBitmap
* WinSalGraphicsImpl::getBitmap( long nX
, long nY
, long nDX
, long nDY
)
919 DBG_ASSERT( !mrParent
.isPrinter(), "No ::GetBitmap() from printer possible!" );
921 WinSalBitmap
* pSalBitmap
= NULL
;
926 HDC hDC
= mrParent
.getHDC();
927 HBITMAP hBmpBitmap
= CreateCompatibleBitmap( hDC
, nDX
, nDY
);
928 HDC hBmpDC
= ImplGetCachedDC( CACHED_HDC_1
, hBmpBitmap
);
931 bRet
= BitBlt( hBmpDC
, 0, 0, (int) nDX
, (int) nDY
, hDC
, (int) nX
, (int) nY
, SRCCOPY
) ? TRUE
: FALSE
;
932 ImplReleaseCachedDC( CACHED_HDC_1
);
936 pSalBitmap
= new WinSalBitmap
;
938 if( !pSalBitmap
->Create( hBmpBitmap
, FALSE
, FALSE
) )
946 // #124826# avoid resource leak! Happens when running without desktop access (remote desktop, service, may be screensavers)
947 DeleteBitmap( hBmpBitmap
);
953 SalColor
WinSalGraphicsImpl::getPixel( long nX
, long nY
)
955 COLORREF aWinCol
= ::GetPixel( mrParent
.getHDC(), (int) nX
, (int) nY
);
957 if ( CLR_INVALID
== aWinCol
)
958 return MAKE_SALCOLOR( 0, 0, 0 );
960 return MAKE_SALCOLOR( GetRValue( aWinCol
),
961 GetGValue( aWinCol
),
962 GetBValue( aWinCol
) );
965 void WinSalGraphicsImpl::invert( long nX
, long nY
, long nWidth
, long nHeight
, SalInvert nFlags
)
967 if ( nFlags
& SAL_INVERT_TRACKFRAME
)
969 HPEN hDotPen
= CreatePen( PS_DOT
, 0, 0 );
970 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hDotPen
);
971 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), GetStockBrush( NULL_BRUSH
) );
972 int nOldROP
= SetROP2( mrParent
.getHDC(), R2_NOT
);
974 WIN_Rectangle( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)(nX
+nWidth
), (int)(nY
+nHeight
) );
976 SetROP2( mrParent
.getHDC(), nOldROP
);
977 SelectPen( mrParent
.getHDC(), hOldPen
);
978 SelectBrush( mrParent
.getHDC(), hOldBrush
);
979 DeletePen( hDotPen
);
981 else if ( nFlags
& SAL_INVERT_50
)
983 SalData
* pSalData
= GetSalData();
984 if ( !pSalData
->mh50Brush
)
986 if ( !pSalData
->mh50Bmp
)
987 pSalData
->mh50Bmp
= ImplLoadSalBitmap( SAL_RESID_BITMAP_50
);
988 pSalData
->mh50Brush
= CreatePatternBrush( pSalData
->mh50Bmp
);
991 COLORREF nOldTextColor
= ::SetTextColor( mrParent
.getHDC(), 0 );
992 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), pSalData
->mh50Brush
);
993 PatBlt( mrParent
.getHDC(), nX
, nY
, nWidth
, nHeight
, PATINVERT
);
994 ::SetTextColor( mrParent
.getHDC(), nOldTextColor
);
995 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1000 aRect
.left
= (int)nX
;
1001 aRect
.top
= (int)nY
;
1002 aRect
.right
= (int)nX
+nWidth
;
1003 aRect
.bottom
= (int)nY
+nHeight
;
1004 ::InvertRect( mrParent
.getHDC(), &aRect
);
1008 void WinSalGraphicsImpl::invert( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, SalInvert nSalFlags
)
1013 HBRUSH hOldBrush
= 0;
1014 COLORREF nOldTextColor
RGB(0,0,0);
1015 int nOldROP
= SetROP2( mrParent
.getHDC(), R2_NOT
);
1017 if ( nSalFlags
& SAL_INVERT_TRACKFRAME
)
1018 hPen
= CreatePen( PS_DOT
, 0, 0 );
1022 if ( nSalFlags
& SAL_INVERT_50
)
1024 SalData
* pSalData
= GetSalData();
1025 if ( !pSalData
->mh50Brush
)
1027 if ( !pSalData
->mh50Bmp
)
1028 pSalData
->mh50Bmp
= ImplLoadSalBitmap( SAL_RESID_BITMAP_50
);
1029 pSalData
->mh50Brush
= CreatePatternBrush( pSalData
->mh50Bmp
);
1032 hBrush
= pSalData
->mh50Brush
;
1035 hBrush
= GetStockBrush( BLACK_BRUSH
);
1037 hPen
= GetStockPen( NULL_PEN
);
1038 nOldTextColor
= ::SetTextColor( mrParent
.getHDC(), 0 );
1039 hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1041 hOldPen
= SelectPen( mrParent
.getHDC(), hPen
);
1044 // for NT, we can handover the array directly
1045 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1046 "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" );
1048 pWinPtAry
= (POINT
*)pPtAry
;
1049 // for Windows 95 and its maximum number of points
1050 if ( nSalFlags
& SAL_INVERT_TRACKFRAME
)
1052 if ( !Polyline( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1053 Polyline( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1057 if ( !WIN_Polygon( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1058 WIN_Polygon( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1061 SetROP2( mrParent
.getHDC(), nOldROP
);
1062 SelectPen( mrParent
.getHDC(), hOldPen
);
1064 if ( nSalFlags
& SAL_INVERT_TRACKFRAME
)
1068 ::SetTextColor( mrParent
.getHDC(), nOldTextColor
);
1069 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1073 sal_uInt16
WinSalGraphicsImpl::GetBitCount() const
1075 return (sal_uInt16
)GetDeviceCaps( mrParent
.getHDC(), BITSPIXEL
);
1078 long WinSalGraphicsImpl::GetGraphicsWidth() const
1080 if( mrParent
.gethWnd() && IsWindow( mrParent
.gethWnd() ) )
1082 WinSalFrame
* pFrame
= GetWindowPtr( mrParent
.gethWnd() );
1085 if( pFrame
->maGeometry
.nWidth
)
1086 return pFrame
->maGeometry
.nWidth
;
1089 // TODO: perhaps not needed, maGeometry should always be up-to-date
1091 GetClientRect( mrParent
.gethWnd(), &aRect
);
1100 void WinSalGraphicsImpl::ResetClipRegion()
1102 if ( mrParent
.mhRegion
)
1104 DeleteRegion( mrParent
.mhRegion
);
1105 mrParent
.mhRegion
= 0;
1108 SelectClipRgn( mrParent
.getHDC(), 0 );
1111 bool WinSalGraphicsImpl::setClipRegion( const vcl::Region
& i_rClip
)
1113 if ( mrParent
.mhRegion
)
1115 DeleteRegion( mrParent
.mhRegion
);
1116 mrParent
.mhRegion
= 0;
1119 bool bUsePolygon(i_rClip
.HasPolyPolygonOrB2DPolyPolygon());
1120 static bool bTryToAvoidPolygon(true);
1122 // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve
1123 // and only contains horizontal/vertical edges. In that case, use the fallback
1124 // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do
1125 // the correct polygon-to-RegionBand transformation.
1126 // Background is that when using the same Rectangle as rectangle or as Polygon
1127 // clip region will lead to different results; the polygon-based one will be
1128 // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This
1129 // again is because of the polygon-nature and it's classic handling when filling.
1130 // This also means that all cases which use a 'true' polygon-based incarnation of
1131 // a vcl::Region should know what they do - it may lead to repaint errors.
1132 if(bUsePolygon
&& bTryToAvoidPolygon
)
1134 const basegfx::B2DPolyPolygon
aPolyPolygon( i_rClip
.GetAsB2DPolyPolygon() );
1136 if(!aPolyPolygon
.areControlPointsUsed())
1138 if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon
))
1140 bUsePolygon
= false;
1147 // #i122149# check the comment above to know that this may lead to potential repaint
1148 // problems. It may be solved (if needed) by scaling the polygon by one in X
1149 // and Y. Currently the workaround to only use it if really unavoidable will
1150 // solve most cases. When someone is really using polygon-based Regions he
1151 // should know what he is doing.
1152 // Added code to do that scaling to check if it works, testing it.
1153 const basegfx::B2DPolyPolygon
aPolyPolygon( i_rClip
.GetAsB2DPolyPolygon() );
1154 const sal_uInt32
nCount(aPolyPolygon
.count());
1158 std::vector
< POINT
> aPolyPoints
;
1159 aPolyPoints
.reserve( 1024 );
1160 std::vector
< INT
> aPolyCounts( nCount
, 0 );
1161 basegfx::B2DHomMatrix aExpand
;
1162 static bool bExpandByOneInXandY(true);
1164 if(bExpandByOneInXandY
)
1166 const basegfx::B2DRange
aRangeS(aPolyPolygon
.getB2DRange());
1167 const basegfx::B2DRange
aRangeT(aRangeS
.getMinimum(), aRangeS
.getMaximum() + basegfx::B2DTuple(1.0, 1.0));
1168 aExpand
= basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS
, aRangeT
));
1171 for(sal_uInt32
a(0); a
< nCount
; a
++)
1173 const basegfx::B2DPolygon
aPoly(
1174 basegfx::tools::adaptiveSubdivideByDistance(
1175 aPolyPolygon
.getB2DPolygon(a
),
1177 const sal_uInt32
nPoints(aPoly
.count());
1178 aPolyCounts
[a
] = nPoints
;
1180 for( sal_uInt32 b
= 0; b
< nPoints
; b
++ )
1182 basegfx::B2DPoint
aPt(aPoly
.getB2DPoint(b
));
1184 if(bExpandByOneInXandY
)
1186 aPt
= aExpand
* aPt
;
1190 // #i122149# do correct rounding
1191 aPOINT
.x
= basegfx::fround(aPt
.getX());
1192 aPOINT
.y
= basegfx::fround(aPt
.getY());
1193 aPolyPoints
.push_back( aPOINT
);
1197 mrParent
.mhRegion
= CreatePolyPolygonRgn( &aPolyPoints
[0], &aPolyCounts
[0], nCount
, ALTERNATE
);
1202 RectangleVector aRectangles
;
1203 i_rClip
.GetRegionRectangles(aRectangles
);
1205 sal_uLong nRectBufSize
= sizeof(RECT
)*aRectangles
.size();
1206 if ( aRectangles
.size() < SAL_CLIPRECT_COUNT
)
1208 if ( !mrParent
.mpStdClipRgnData
)
1209 mrParent
.mpStdClipRgnData
= (RGNDATA
*)new BYTE
[sizeof(RGNDATA
)-1+(SAL_CLIPRECT_COUNT
*sizeof(RECT
))];
1210 mrParent
.mpClipRgnData
= mrParent
.mpStdClipRgnData
;
1213 mrParent
.mpClipRgnData
= (RGNDATA
*)new BYTE
[sizeof(RGNDATA
)-1+nRectBufSize
];
1214 mrParent
.mpClipRgnData
->rdh
.dwSize
= sizeof( RGNDATAHEADER
);
1215 mrParent
.mpClipRgnData
->rdh
.iType
= RDH_RECTANGLES
;
1216 mrParent
.mpClipRgnData
->rdh
.nCount
= aRectangles
.size();
1217 mrParent
.mpClipRgnData
->rdh
.nRgnSize
= nRectBufSize
;
1218 RECT
* pBoundRect
= &(mrParent
.mpClipRgnData
->rdh
.rcBound
);
1219 SetRectEmpty( pBoundRect
);
1220 RECT
* pNextClipRect
= (RECT
*)(&(mrParent
.mpClipRgnData
->Buffer
));
1221 bool bFirstClipRect
= true;
1223 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
1225 const long nW(aRectIter
->GetWidth());
1226 const long nH(aRectIter
->GetHeight());
1230 const long nRight(aRectIter
->Left() + nW
);
1231 const long nBottom(aRectIter
->Top() + nH
);
1235 pBoundRect
->left
= aRectIter
->Left();
1236 pBoundRect
->top
= aRectIter
->Top();
1237 pBoundRect
->right
= nRight
;
1238 pBoundRect
->bottom
= nBottom
;
1239 bFirstClipRect
= false;
1243 if(aRectIter
->Left() < pBoundRect
->left
)
1245 pBoundRect
->left
= (int)aRectIter
->Left();
1248 if(aRectIter
->Top() < pBoundRect
->top
)
1250 pBoundRect
->top
= (int)aRectIter
->Top();
1253 if(nRight
> pBoundRect
->right
)
1255 pBoundRect
->right
= (int)nRight
;
1258 if(nBottom
> pBoundRect
->bottom
)
1260 pBoundRect
->bottom
= (int)nBottom
;
1264 pNextClipRect
->left
= (int)aRectIter
->Left();
1265 pNextClipRect
->top
= (int)aRectIter
->Top();
1266 pNextClipRect
->right
= (int)nRight
;
1267 pNextClipRect
->bottom
= (int)nBottom
;
1272 mrParent
.mpClipRgnData
->rdh
.nCount
--;
1273 mrParent
.mpClipRgnData
->rdh
.nRgnSize
-= sizeof( RECT
);
1277 // create clip region from ClipRgnData
1278 if(0 == mrParent
.mpClipRgnData
->rdh
.nCount
)
1280 // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given
1281 // that contains no polygons or only empty ones (no width/height). This is
1282 // perfectly fine and we are done, except setting it (see end of method)
1284 else if(1 == mrParent
.mpClipRgnData
->rdh
.nCount
)
1286 RECT
* pRect
= &(mrParent
.mpClipRgnData
->rdh
.rcBound
);
1287 mrParent
.mhRegion
= CreateRectRgn( pRect
->left
, pRect
->top
,
1288 pRect
->right
, pRect
->bottom
);
1290 else if(mrParent
.mpClipRgnData
->rdh
.nCount
> 1)
1292 sal_uLong nSize
= mrParent
.mpClipRgnData
->rdh
.nRgnSize
+sizeof(RGNDATAHEADER
);
1293 mrParent
.mhRegion
= ExtCreateRegion( NULL
, nSize
, mrParent
.mpClipRgnData
);
1295 // if ExtCreateRegion(...) is not supported
1296 if( !mrParent
.mhRegion
)
1298 RGNDATAHEADER
* pHeader
= (RGNDATAHEADER
*) mrParent
.mpClipRgnData
;
1300 if( pHeader
->nCount
)
1302 RECT
* pRect
= (RECT
*) mrParent
.mpClipRgnData
->Buffer
;
1303 mrParent
.mhRegion
= CreateRectRgn( pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1306 for( sal_uLong n
= 1; n
< pHeader
->nCount
; n
++, pRect
++ )
1308 HRGN hRgn
= CreateRectRgn( pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1309 CombineRgn( mrParent
.mhRegion
, mrParent
.mhRegion
, hRgn
, RGN_OR
);
1310 DeleteRegion( hRgn
);
1315 if ( mrParent
.mpClipRgnData
!= mrParent
.mpStdClipRgnData
)
1316 delete [] mrParent
.mpClipRgnData
;
1320 if( mrParent
.mhRegion
)
1322 SelectClipRgn( mrParent
.getHDC(), mrParent
.mhRegion
);
1324 // debug code if you weant to check range of the newly applied ClipRegion
1326 //const int aRegionType = GetRgnBox(mrParent.mhRegion, &aBound);
1332 // #i123585# See above, this is a valid case, execute it
1333 SelectClipRgn( mrParent
.getHDC(), 0 );
1336 // #i123585# retval no longer dependent of mrParent.mhRegion, see TaskId comments above
1340 void WinSalGraphicsImpl::SetLineColor()
1342 // create and select new pen
1343 HPEN hNewPen
= GetStockPen( NULL_PEN
);
1344 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hNewPen
);
1346 // destroy or save old pen
1353 mrParent
.mhDefPen
= hOldPen
;
1361 void WinSalGraphicsImpl::SetLineColor( SalColor nSalColor
)
1363 maLineColor
= nSalColor
;
1364 COLORREF nPenColor
= PALETTERGB( SALCOLOR_RED( nSalColor
),
1365 SALCOLOR_GREEN( nSalColor
),
1366 SALCOLOR_BLUE( nSalColor
) );
1368 bool bStockPen
= FALSE
;
1370 // search for stock pen (only screen, because printer have problems,
1371 // when we use stock objects)
1372 if ( !mrParent
.isPrinter() )
1374 SalData
* pSalData
= GetSalData();
1375 for ( sal_uInt16 i
= 0; i
< pSalData
->mnStockPenCount
; i
++ )
1377 if ( nPenColor
== pSalData
->maStockPenColorAry
[i
] )
1379 hNewPen
= pSalData
->mhStockPenAry
[i
];
1389 if ( !mrParent
.isPrinter() )
1391 if ( GetSalData()->mhDitherPal
&& ImplIsSysColorEntry( nSalColor
) )
1392 nPenColor
= PALRGB_TO_RGB( nPenColor
);
1395 hNewPen
= CreatePen( PS_SOLID
, mrParent
.mnPenWidth
, nPenColor
);
1400 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hNewPen
);
1402 // destroy or save old pen
1409 mrParent
.mhDefPen
= hOldPen
;
1412 mnPenColor
= nPenColor
;
1415 mbStockPen
= bStockPen
;
1418 void WinSalGraphicsImpl::SetFillColor()
1420 // create and select new brush
1421 HBRUSH hNewBrush
= GetStockBrush( NULL_BRUSH
);
1422 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hNewBrush
);
1424 // destroy or save old brush
1427 if ( !mbStockBrush
)
1428 DeleteBrush( mhBrush
);
1431 mrParent
.mhDefBrush
= hOldBrush
;
1434 mhBrush
= hNewBrush
;
1436 mbStockBrush
= TRUE
;
1439 void WinSalGraphicsImpl::SetFillColor( SalColor nSalColor
)
1441 maFillColor
= nSalColor
;
1442 SalData
* pSalData
= GetSalData();
1443 BYTE nRed
= SALCOLOR_RED( nSalColor
);
1444 BYTE nGreen
= SALCOLOR_GREEN( nSalColor
);
1445 BYTE nBlue
= SALCOLOR_BLUE( nSalColor
);
1446 COLORREF nBrushColor
= PALETTERGB( nRed
, nGreen
, nBlue
);
1447 HBRUSH hNewBrush
= 0;
1448 bool bStockBrush
= FALSE
;
1450 // search for stock brush (only screen, because printer have problems,
1451 // when we use stock objects)
1452 if ( !mrParent
.isPrinter() )
1454 for ( sal_uInt16 i
= 0; i
< pSalData
->mnStockBrushCount
; i
++ )
1456 if ( nBrushColor
== pSalData
->maStockBrushColorAry
[ i
] )
1458 hNewBrush
= pSalData
->mhStockBrushAry
[i
];
1468 if ( mrParent
.isPrinter() || !pSalData
->mhDitherDIB
)
1469 hNewBrush
= CreateSolidBrush( nBrushColor
);
1472 if ( 24 == ((BITMAPINFOHEADER
*)pSalData
->mpDitherDIB
)->biBitCount
)
1474 BYTE
* pTmp
= pSalData
->mpDitherDIBData
;
1475 long* pDitherDiff
= pSalData
->mpDitherDiff
;
1476 BYTE
* pDitherLow
= pSalData
->mpDitherLow
;
1477 BYTE
* pDitherHigh
= pSalData
->mpDitherHigh
;
1479 for( long nY
= 0L; nY
< 8L; nY
++ )
1481 for( long nX
= 0L; nX
< 8L; nX
++ )
1483 const long nThres
= aOrdDither16Bit
[ nY
][ nX
];
1484 *pTmp
++ = DMAP( nBlue
, nThres
);
1485 *pTmp
++ = DMAP( nGreen
, nThres
);
1486 *pTmp
++ = DMAP( nRed
, nThres
);
1490 hNewBrush
= CreateDIBPatternBrush( pSalData
->mhDitherDIB
, DIB_RGB_COLORS
);
1492 else if ( ImplIsSysColorEntry( nSalColor
) )
1494 nBrushColor
= PALRGB_TO_RGB( nBrushColor
);
1495 hNewBrush
= CreateSolidBrush( nBrushColor
);
1497 else if ( ImplIsPaletteEntry( nRed
, nGreen
, nBlue
) )
1498 hNewBrush
= CreateSolidBrush( nBrushColor
);
1501 BYTE
* pTmp
= pSalData
->mpDitherDIBData
;
1502 long* pDitherDiff
= pSalData
->mpDitherDiff
;
1503 BYTE
* pDitherLow
= pSalData
->mpDitherLow
;
1504 BYTE
* pDitherHigh
= pSalData
->mpDitherHigh
;
1506 for ( long nY
= 0L; nY
< 8L; nY
++ )
1508 for ( long nX
= 0L; nX
< 8L; nX
++ )
1510 const long nThres
= aOrdDither8Bit
[ nY
][ nX
];
1511 *pTmp
= DMAP( nRed
, nThres
) + DMAP( nGreen
, nThres
) * 6 + DMAP( nBlue
, nThres
) * 36;
1516 hNewBrush
= CreateDIBPatternBrush( pSalData
->mhDitherDIB
, DIB_PAL_COLORS
);
1520 bStockBrush
= FALSE
;
1524 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hNewBrush
);
1526 // destroy or save old brush
1529 if ( !mbStockBrush
)
1530 DeleteBrush( mhBrush
);
1533 mrParent
.mhDefBrush
= hOldBrush
;
1536 mnBrushColor
= nBrushColor
;
1537 mhBrush
= hNewBrush
;
1539 mbStockBrush
= bStockBrush
;
1542 void WinSalGraphicsImpl::SetXORMode( bool bSet
, bool )
1545 ::SetROP2( mrParent
.getHDC(), bSet
? R2_XORPEN
: R2_COPYPEN
);
1548 void WinSalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor
)
1550 SetLineColor( ImplGetROPSalColor( nROPColor
) );
1553 void WinSalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor
)
1555 SetFillColor( ImplGetROPSalColor( nROPColor
) );
1558 void WinSalGraphicsImpl::drawPixel( long nX
, long nY
)
1562 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1563 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1564 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)1, (int)1, PATINVERT
);
1565 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1566 DeleteBrush( hBrush
);
1569 SetPixel( mrParent
.getHDC(), (int)nX
, (int)nY
, mnPenColor
);
1572 void WinSalGraphicsImpl::drawPixel( long nX
, long nY
, SalColor nSalColor
)
1574 COLORREF nCol
= PALETTERGB( SALCOLOR_RED( nSalColor
),
1575 SALCOLOR_GREEN( nSalColor
),
1576 SALCOLOR_BLUE( nSalColor
) );
1578 if ( !mrParent
.isPrinter() &&
1579 GetSalData()->mhDitherPal
&&
1580 ImplIsSysColorEntry( nSalColor
) )
1581 nCol
= PALRGB_TO_RGB( nCol
);
1585 HBRUSH hBrush
= CreateSolidBrush( nCol
);
1586 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1587 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)1, (int)1, PATINVERT
);
1588 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1589 DeleteBrush( hBrush
);
1592 ::SetPixel( mrParent
.getHDC(), (int)nX
, (int)nY
, nCol
);
1595 void WinSalGraphicsImpl::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
1597 MoveToEx( mrParent
.getHDC(), (int)nX1
, (int)nY1
, NULL
);
1599 // we must paint the endpoint
1600 int bPaintEnd
= TRUE
;
1618 LineTo( mrParent
.getHDC(), (int)nX2
, (int)nY2
);
1620 if ( bPaintEnd
&& !mrParent
.isPrinter() )
1624 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1625 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1626 PatBlt( mrParent
.getHDC(), (int)nX2
, (int)nY2
, (int)1, (int)1, PATINVERT
);
1627 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1628 DeleteBrush( hBrush
);
1631 SetPixel( mrParent
.getHDC(), (int)nX2
, (int)nY2
, mnPenColor
);
1635 void WinSalGraphicsImpl::drawRect( long nX
, long nY
, long nWidth
, long nHeight
)
1639 if ( !mrParent
.isPrinter() )
1641 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)nWidth
, (int)nHeight
,
1642 mbXORMode
? PATINVERT
: PATCOPY
);
1649 aWinRect
.right
= nX
+nWidth
;
1650 aWinRect
.bottom
= nY
+nHeight
;
1651 ::FillRect( mrParent
.getHDC(), &aWinRect
, mhBrush
);
1655 WIN_Rectangle( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)(nX
+nWidth
), (int)(nY
+nHeight
) );
1658 void WinSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1660 // for NT, we can handover the array directly
1661 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1662 "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" );
1664 POINT
* pWinPtAry
= (POINT
*)pPtAry
;
1666 // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN)
1667 // we must paint the endpoint for last line
1668 BOOL bPaintEnd
= TRUE
;
1669 if ( pWinPtAry
[nPoints
-2].x
== pWinPtAry
[nPoints
-1].x
)
1672 if ( pWinPtAry
[nPoints
-2].y
<= pWinPtAry
[nPoints
-1].y
)
1673 pWinPtAry
[nPoints
-1].y
++;
1675 pWinPtAry
[nPoints
-1].y
--;
1677 if ( pWinPtAry
[nPoints
-2].y
== pWinPtAry
[nPoints
-1].y
)
1680 if ( pWinPtAry
[nPoints
-2].x
<= pWinPtAry
[nPoints
-1].x
)
1681 pWinPtAry
[nPoints
-1].x
++;
1683 pWinPtAry
[nPoints
-1].x
--;
1686 // for Windows 95 and its maximum number of points
1687 if ( !Polyline( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1688 Polyline( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1690 if ( bPaintEnd
&& !mrParent
.isPrinter() )
1694 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1695 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1696 PatBlt( mrParent
.getHDC(), (int)(pWinPtAry
[nPoints
-1].x
), (int)(pWinPtAry
[nPoints
-1].y
), (int)1, (int)1, PATINVERT
);
1697 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1698 DeleteBrush( hBrush
);
1701 SetPixel( mrParent
.getHDC(), (int)(pWinPtAry
[nPoints
-1].x
), (int)(pWinPtAry
[nPoints
-1].y
), mnPenColor
);
1705 void WinSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1707 // for NT, we can handover the array directly
1708 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1709 "WinSalGraphicsImpl::DrawPolygon(): POINT != SalPoint" );
1711 POINT
* pWinPtAry
= (POINT
*)pPtAry
;
1712 // for Windows 95 and its maximum number of points
1713 if ( !WIN_Polygon( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1714 WIN_Polygon( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1717 void WinSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
1718 PCONSTSALPOINT
* pPtAry
)
1720 UINT aWinPointAry
[SAL_POLYPOLYCOUNT_STACKBUF
];
1722 UINT nPolyPolyPoints
= 0;
1726 if ( nPoly
<= SAL_POLYPOLYCOUNT_STACKBUF
)
1727 pWinPointAry
= aWinPointAry
;
1729 pWinPointAry
= new UINT
[nPoly
];
1731 for ( i
= 0; i
< (UINT
)nPoly
; i
++ )
1733 nPoints
= (UINT
)pPoints
[i
]+1;
1734 pWinPointAry
[i
] = nPoints
;
1735 nPolyPolyPoints
+= nPoints
;
1738 POINT aWinPointAryAry
[SAL_POLYPOLYPOINTS_STACKBUF
];
1739 POINT
* pWinPointAryAry
;
1740 if ( nPolyPolyPoints
<= SAL_POLYPOLYPOINTS_STACKBUF
)
1741 pWinPointAryAry
= aWinPointAryAry
;
1743 pWinPointAryAry
= new POINT
[nPolyPolyPoints
];
1744 // for NT, we can handover the array directly
1745 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1746 "WinSalGraphicsImpl::DrawPolyPolygon(): POINT != SalPoint" );
1748 for ( i
= 0; i
< (UINT
)nPoly
; i
++ )
1750 nPoints
= pWinPointAry
[i
];
1751 const SalPoint
* pPolyAry
= pPtAry
[i
];
1752 memcpy( pWinPointAryAry
+n
, pPolyAry
, (nPoints
-1)*sizeof(POINT
) );
1753 pWinPointAryAry
[n
+nPoints
-1] = pWinPointAryAry
[n
];
1757 if ( !WIN_PolyPolygon( mrParent
.getHDC(), pWinPointAryAry
, (int*)pWinPointAry
, (UINT
)nPoly
) &&
1758 (nPolyPolyPoints
> MAX_64KSALPOINTS
) )
1760 nPolyPolyPoints
= 0;
1764 nPolyPolyPoints
+= pWinPointAry
[(UINT
)nPoly
];
1767 while ( nPolyPolyPoints
< MAX_64KSALPOINTS
);
1769 if ( pWinPointAry
[(UINT
)nPoly
] > MAX_64KSALPOINTS
)
1770 pWinPointAry
[(UINT
)nPoly
] = MAX_64KSALPOINTS
;
1772 WIN_Polygon( mrParent
.getHDC(), pWinPointAryAry
, *pWinPointAry
);
1774 WIN_PolyPolygon( mrParent
.getHDC(), pWinPointAryAry
, (int*)pWinPointAry
, nPoly
);
1777 if ( pWinPointAry
!= aWinPointAry
)
1778 delete [] pWinPointAry
;
1779 if ( pWinPointAryAry
!= aWinPointAryAry
)
1780 delete [] pWinPointAryAry
;
1783 bool WinSalGraphicsImpl::drawPolyLineBezier( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, const BYTE
* pFlgAry
)
1785 #ifdef USE_GDI_BEZIERS
1786 // for NT, we can handover the array directly
1787 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1788 "WinSalGraphicsImpl::DrawPolyLineBezier(): POINT != SalPoint" );
1790 ImplRenderPath( mrParent
.getHDC(), nPoints
, pPtAry
, pFlgAry
);
1798 bool WinSalGraphicsImpl::drawPolygonBezier( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, const BYTE
* pFlgAry
)
1800 #ifdef USE_GDI_BEZIERS
1801 // for NT, we can handover the array directly
1802 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1803 "WinSalGraphicsImpl::DrawPolygonBezier(): POINT != SalPoint" );
1805 POINT aStackAry1
[SAL_POLY_STACKBUF
];
1806 BYTE aStackAry2
[SAL_POLY_STACKBUF
];
1807 POINT
* pWinPointAry
;
1809 if( nPoints
> SAL_POLY_STACKBUF
)
1811 pWinPointAry
= new POINT
[ nPoints
];
1812 pWinFlagAry
= new BYTE
[ nPoints
];
1816 pWinPointAry
= aStackAry1
;
1817 pWinFlagAry
= aStackAry2
;
1820 sal_uInt32
nPoints_i32(nPoints
);
1821 ImplPreparePolyDraw(true, 1, &nPoints_i32
, &pPtAry
, &pFlgAry
, pWinPointAry
, pWinFlagAry
);
1825 if( BeginPath( mrParent
.getHDC() ) )
1827 PolyDraw(mrParent
.getHDC(), pWinPointAry
, pWinFlagAry
, nPoints
);
1829 if( EndPath( mrParent
.getHDC() ) )
1831 if( StrokeAndFillPath( mrParent
.getHDC() ) )
1836 if( pWinPointAry
!= aStackAry1
)
1838 delete [] pWinPointAry
;
1839 delete [] pWinFlagAry
;
1848 bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
1849 const SalPoint
* const* pPtAry
, const BYTE
* const* pFlgAry
)
1851 #ifdef USE_GDI_BEZIERS
1852 // for NT, we can handover the array directly
1853 DBG_ASSERT( sizeof( POINT
) == sizeof( SalPoint
),
1854 "WinSalGraphicsImpl::DrawPolyPolygonBezier(): POINT != SalPoint" );
1856 sal_uLong nCurrPoly
, nTotalPoints
;
1857 const sal_uInt32
* pCurrPoints
= pPoints
;
1858 for( nCurrPoly
=0, nTotalPoints
=0; nCurrPoly
<nPoly
; ++nCurrPoly
)
1859 nTotalPoints
+= *pCurrPoints
++;
1861 POINT aStackAry1
[SAL_POLY_STACKBUF
];
1862 BYTE aStackAry2
[SAL_POLY_STACKBUF
];
1863 POINT
* pWinPointAry
;
1865 if( nTotalPoints
> SAL_POLY_STACKBUF
)
1867 pWinPointAry
= new POINT
[ nTotalPoints
];
1868 pWinFlagAry
= new BYTE
[ nTotalPoints
];
1872 pWinPointAry
= aStackAry1
;
1873 pWinFlagAry
= aStackAry2
;
1876 ImplPreparePolyDraw(true, nPoly
, pPoints
, pPtAry
, pFlgAry
, pWinPointAry
, pWinFlagAry
);
1880 if( BeginPath( mrParent
.getHDC() ) )
1882 PolyDraw(mrParent
.getHDC(), pWinPointAry
, pWinFlagAry
, nTotalPoints
);
1884 if( EndPath( mrParent
.getHDC() ) )
1886 if( StrokeAndFillPath( mrParent
.getHDC() ) )
1891 if( pWinPointAry
!= aStackAry1
)
1893 delete [] pWinPointAry
;
1894 delete [] pWinFlagAry
;
1903 void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath
*pPath
, const basegfx::B2DPolygon
& rPolygon
, bool bNoLineJoin
)
1905 sal_uInt32
nCount(rPolygon
.count());
1909 const sal_uInt32
nEdgeCount(rPolygon
.isClosed() ? nCount
: nCount
- 1);
1910 const bool bControls(rPolygon
.areControlPointsUsed());
1911 basegfx::B2DPoint
aCurr(rPolygon
.getB2DPoint(0));
1913 for(sal_uInt32
a(0); a
< nEdgeCount
; a
++)
1915 const sal_uInt32
nNextIndex((a
+ 1) % nCount
);
1916 const basegfx::B2DPoint
aNext(rPolygon
.getB2DPoint(nNextIndex
));
1918 if(bControls
&& (rPolygon
.isNextControlPointUsed(a
) || rPolygon
.isPrevControlPointUsed(nNextIndex
)))
1920 const basegfx::B2DPoint
aCa(rPolygon
.getNextControlPoint(a
));
1921 const basegfx::B2DPoint
aCb(rPolygon
.getPrevControlPoint(nNextIndex
));
1923 Gdiplus::DllExports::GdipAddPathBezier(pPath
,
1924 aCurr
.getX(), aCurr
.getY(),
1925 aCa
.getX(), aCa
.getY(),
1926 aCb
.getX(), aCb
.getY(),
1927 aNext
.getX(), aNext
.getY());
1931 Gdiplus::DllExports::GdipAddPathLine(pPath
, aCurr
.getX(), aCurr
.getY(), aNext
.getX(), aNext
.getY());
1934 if(a
+ 1 < nEdgeCount
)
1940 Gdiplus::DllExports::GdipStartPathFigure(pPath
);
1947 void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath
*pPath
, const basegfx::B2DPolygon
& rPolygon
, bool bNoLineJoin
)
1949 sal_uInt32
nCount(rPolygon
.count());
1953 const sal_uInt32
nEdgeCount(rPolygon
.isClosed() ? nCount
: nCount
- 1);
1954 const bool bControls(rPolygon
.areControlPointsUsed());
1955 basegfx::B2DPoint
aCurr(rPolygon
.getB2DPoint(0));
1957 for(sal_uInt32
a(0); a
< nEdgeCount
; a
++)
1959 const sal_uInt32
nNextIndex((a
+ 1) % nCount
);
1960 const basegfx::B2DPoint
aNext(rPolygon
.getB2DPoint(nNextIndex
));
1962 if(bControls
&& (rPolygon
.isNextControlPointUsed(a
) || rPolygon
.isPrevControlPointUsed(nNextIndex
)))
1964 const basegfx::B2DPoint
aCa(rPolygon
.getNextControlPoint(a
));
1965 const basegfx::B2DPoint
aCb(rPolygon
.getPrevControlPoint(nNextIndex
));
1967 Gdiplus::DllExports::GdipAddPathBezier(
1969 aCurr
.getX(), aCurr
.getY(),
1970 aCa
.getX(), aCa
.getY(),
1971 aCb
.getX(), aCb
.getY(),
1972 aNext
.getX(), aNext
.getY());
1976 Gdiplus::DllExports::GdipAddPathLine(pPath
, aCurr
.getX(), aCurr
.getY(), aNext
.getX(), aNext
.getY());
1979 if(a
+ 1 < nEdgeCount
)
1985 Gdiplus::DllExports::GdipStartPathFigure(pPath
);
1992 bool WinSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon
& rPolyPolygon
, double fTransparency
)
1994 const sal_uInt32
nCount(rPolyPolygon
.count());
1996 if(mbBrush
&& nCount
&& (fTransparency
>= 0.0 && fTransparency
< 1.0))
1998 Gdiplus::GpGraphics
*pGraphics
= NULL
;
1999 Gdiplus::DllExports::GdipCreateFromHDC(mrParent
.getHDC(), &pGraphics
);
2000 const sal_uInt8
aTrans((sal_uInt8
)255 - (sal_uInt8
)basegfx::fround(fTransparency
* 255.0));
2001 Gdiplus::Color
aTestColor(aTrans
, SALCOLOR_RED(maFillColor
), SALCOLOR_GREEN(maFillColor
), SALCOLOR_BLUE(maFillColor
));
2002 Gdiplus::GpSolidFill
*pTestBrush
;
2003 Gdiplus::DllExports::GdipCreateSolidFill(aTestColor
.GetValue(), &pTestBrush
);
2004 Gdiplus::GpPath
*pPath
= NULL
;
2005 Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate
, &pPath
);
2007 for(sal_uInt32
a(0); a
< nCount
; a
++)
2011 Gdiplus::DllExports::GdipStartPathFigure(pPath
); // #i101491# not needed for first run
2014 impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath
, rPolyPolygon
.getB2DPolygon(a
), false);
2015 Gdiplus::DllExports::GdipClosePathFigure(pPath
);
2018 if(mrParent
.getAntiAliasB2DDraw())
2020 Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics
, Gdiplus::SmoothingModeAntiAlias
);
2024 Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics
, Gdiplus::SmoothingModeNone
);
2027 if(mrParent
.isPrinter())
2030 // Normally GdiPlus should not be used for printing at all since printers cannot
2031 // print transparent filled polygon geometry and normally this does not happen
2032 // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation
2033 // and no transparent parts should remain for printing. But this can be overridden
2034 // by the user and thus happens. This call can only come (currently) from
2035 // OutputDevice::DrawTransparent, see comments there with the same TaskID.
2036 // If it is used, the mapping for the printer is wrong and needs to be corrected. I
2037 // checked that there is *no* transformation set and estimated that a stable factor
2038 // dependent of the printer's DPI is used. Create and set a transformation here to
2040 Gdiplus::REAL aDpiX
;
2041 Gdiplus::DllExports::GdipGetDpiX(pGraphics
, &aDpiX
);
2042 Gdiplus::REAL aDpiY
;
2043 Gdiplus::DllExports::GdipGetDpiY(pGraphics
, &aDpiY
);
2045 Gdiplus::DllExports::GdipResetWorldTransform(pGraphics
);
2046 Gdiplus::DllExports::GdipScaleWorldTransform(pGraphics
, Gdiplus::REAL(100.0) / aDpiX
, Gdiplus::REAL(100.0) / aDpiY
, Gdiplus::MatrixOrderAppend
);
2049 Gdiplus::DllExports::GdipFillPath(pGraphics
, pTestBrush
, pPath
);
2051 Gdiplus::DllExports::GdipDeletePath(pPath
);
2052 Gdiplus::DllExports::GdipDeleteGraphics(pGraphics
);
2058 bool WinSalGraphicsImpl::drawPolyLine(
2059 const basegfx::B2DPolygon
& rPolygon
,
2060 double fTransparency
,
2061 const basegfx::B2DVector
& rLineWidths
,
2062 basegfx::B2DLineJoin eLineJoin
,
2063 com::sun::star::drawing::LineCap eLineCap
)
2065 const sal_uInt32
nCount(rPolygon
.count());
2069 Gdiplus::GpGraphics
*pGraphics
= NULL
;
2070 Gdiplus::DllExports::GdipCreateFromHDC(mrParent
.getHDC(), &pGraphics
);
2071 const sal_uInt8 aTrans
= (sal_uInt8
)basegfx::fround( 255 * (1.0 - fTransparency
) );
2072 Gdiplus::Color
aTestColor(aTrans
, SALCOLOR_RED(maLineColor
), SALCOLOR_GREEN(maLineColor
), SALCOLOR_BLUE(maLineColor
));
2073 Gdiplus::GpPen
*pTestPen
= NULL
;
2074 Gdiplus::DllExports::GdipCreatePen1(aTestColor
.GetValue(), Gdiplus::REAL(rLineWidths
.getX()), Gdiplus::UnitWorld
, &pTestPen
);
2075 Gdiplus::GpPath
*pPath
;
2076 Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate
, &pPath
);
2077 bool bNoLineJoin(false);
2081 default : // basegfx::B2DLINEJOIN_NONE :
2083 if(basegfx::fTools::more(rLineWidths
.getX(), 0.0))
2089 case basegfx::B2DLINEJOIN_BEVEL
:
2091 Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen
, Gdiplus::LineJoinBevel
);
2094 case basegfx::B2DLINEJOIN_MIDDLE
:
2095 case basegfx::B2DLINEJOIN_MITER
:
2097 const Gdiplus::REAL
aMiterLimit(15.0);
2098 Gdiplus::DllExports::GdipSetPenMiterLimit(pTestPen
, aMiterLimit
);
2099 Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen
, Gdiplus::LineJoinMiter
);
2102 case basegfx::B2DLINEJOIN_ROUND
:
2104 Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen
, Gdiplus::LineJoinRound
);
2111 default: /*com::sun::star::drawing::LineCap_BUTT*/
2116 case com::sun::star::drawing::LineCap_ROUND
:
2118 Gdiplus::DllExports::GdipSetPenStartCap(pTestPen
, Gdiplus::LineCapRound
);
2119 Gdiplus::DllExports::GdipSetPenEndCap(pTestPen
, Gdiplus::LineCapRound
);
2122 case com::sun::star::drawing::LineCap_SQUARE
:
2124 Gdiplus::DllExports::GdipSetPenStartCap(pTestPen
, Gdiplus::LineCapSquare
);
2125 Gdiplus::DllExports::GdipSetPenEndCap(pTestPen
, Gdiplus::LineCapSquare
);
2130 if(nCount
> 250 && basegfx::fTools::more(rLineWidths
.getX(), 1.5))
2132 impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath
, rPolygon
, bNoLineJoin
);
2136 impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath
, rPolygon
, bNoLineJoin
);
2139 if(rPolygon
.isClosed() && !bNoLineJoin
)
2141 // #i101491# needed to create the correct line joins
2142 Gdiplus::DllExports::GdipClosePathFigure(pPath
);
2145 if(mrParent
.getAntiAliasB2DDraw())
2147 Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics
, Gdiplus::SmoothingModeAntiAlias
);
2151 Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics
, Gdiplus::SmoothingModeNone
);
2154 Gdiplus::DllExports::GdipDrawPath(pGraphics
, pTestPen
, pPath
);
2156 Gdiplus::DllExports::GdipDeletePath(pPath
);
2157 Gdiplus::DllExports::GdipDeletePen(pTestPen
);
2158 Gdiplus::DllExports::GdipDeleteGraphics(pGraphics
);
2164 void paintToGdiPlus(
2165 Gdiplus::Graphics
& rGraphics
,
2166 const SalTwoRect
& rTR
,
2167 Gdiplus::Bitmap
& rBitmap
)
2169 // only parts of source are used
2170 Gdiplus::PointF aDestPoints
[3];
2171 Gdiplus::ImageAttributes aAttributes
;
2173 // define target region as paralellogram
2174 aDestPoints
[0].X
= Gdiplus::REAL(rTR
.mnDestX
);
2175 aDestPoints
[0].Y
= Gdiplus::REAL(rTR
.mnDestY
);
2176 aDestPoints
[1].X
= Gdiplus::REAL(rTR
.mnDestX
+ rTR
.mnDestWidth
);
2177 aDestPoints
[1].Y
= Gdiplus::REAL(rTR
.mnDestY
);
2178 aDestPoints
[2].X
= Gdiplus::REAL(rTR
.mnDestX
);
2179 aDestPoints
[2].Y
= Gdiplus::REAL(rTR
.mnDestY
+ rTR
.mnDestHeight
);
2181 aAttributes
.SetWrapMode(Gdiplus::WrapModeTileFlipXY
);
2183 rGraphics
.DrawImage(
2187 Gdiplus::REAL(rTR
.mnSrcX
),
2188 Gdiplus::REAL(rTR
.mnSrcY
),
2189 Gdiplus::REAL(rTR
.mnSrcWidth
),
2190 Gdiplus::REAL(rTR
.mnSrcHeight
),
2197 void setInterpolationMode(
2198 Gdiplus::Graphics
& rGraphics
,
2199 const long& rSrcWidth
,
2200 const long& rDestWidth
,
2201 const long& rSrcHeight
,
2202 const long& rDestHeight
)
2204 const bool bSameWidth(rSrcWidth
== rDestWidth
);
2205 const bool bSameHeight(rSrcHeight
== rDestHeight
);
2207 if(bSameWidth
&& bSameHeight
)
2210 //Gdiplus::InterpolationModeInvalid is missing on mingw
2211 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2213 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeInvalid
);
2216 else if(rDestWidth
> rSrcWidth
&& rDestHeight
> rSrcHeight
)
2218 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2220 else if(rDestWidth
< rSrcWidth
&& rDestHeight
< rSrcHeight
)
2222 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeBicubic
);
2226 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2230 bool WinSalGraphicsImpl::tryDrawBitmapGdiPlus(const SalTwoRect
& rTR
, const SalBitmap
& rSrcBitmap
)
2232 if(rTR
.mnSrcWidth
&& rTR
.mnSrcHeight
&& rTR
.mnDestWidth
&& rTR
.mnDestHeight
)
2234 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSrcBitmap
);
2235 GdiPlusBmpPtr
aARGB(rSalBitmap
.ImplGetGdiPlusBitmap());
2239 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2241 setInterpolationMode(
2260 bool WinSalGraphicsImpl::blendBitmap(
2267 bool WinSalGraphicsImpl::blendAlphaBitmap(
2276 bool WinSalGraphicsImpl::drawAlphaBitmap(
2277 const SalTwoRect
& rTR
,
2278 const SalBitmap
& rSrcBitmap
,
2279 const SalBitmap
& rAlphaBmp
)
2281 if(rTR
.mnSrcWidth
&& rTR
.mnSrcHeight
&& rTR
.mnDestWidth
&& rTR
.mnDestHeight
)
2283 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSrcBitmap
);
2284 const WinSalBitmap
& rSalAlpha
= static_cast< const WinSalBitmap
& >(rAlphaBmp
);
2285 GdiPlusBmpPtr
aARGB(rSalBitmap
.ImplGetGdiPlusBitmap(&rSalAlpha
));
2289 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2291 setInterpolationMode(
2310 bool WinSalGraphicsImpl::drawTransformedBitmap(
2311 const basegfx::B2DPoint
& rNull
,
2312 const basegfx::B2DPoint
& rX
,
2313 const basegfx::B2DPoint
& rY
,
2314 const SalBitmap
& rSourceBitmap
,
2315 const SalBitmap
* pAlphaBitmap
)
2317 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSourceBitmap
);
2318 const WinSalBitmap
* pSalAlpha
= static_cast< const WinSalBitmap
* >(pAlphaBitmap
);
2319 GdiPlusBmpPtr
aARGB(rSalBitmap
.ImplGetGdiPlusBitmap(pSalAlpha
));
2323 const long nSrcWidth(aARGB
->GetWidth());
2324 const long nSrcHeight(aARGB
->GetHeight());
2326 if(nSrcWidth
&& nSrcHeight
)
2328 const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX
- rNull
).getLength()));
2329 const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY
- rNull
).getLength()));
2331 if(nDestWidth
&& nDestHeight
)
2333 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2334 Gdiplus::PointF aDestPoints
[3];
2335 Gdiplus::ImageAttributes aAttributes
;
2337 setInterpolationMode(
2344 // this mode is only capable of drawing the whole bitmap to a paralellogram
2345 aDestPoints
[0].X
= Gdiplus::REAL(rNull
.getX());
2346 aDestPoints
[0].Y
= Gdiplus::REAL(rNull
.getY());
2347 aDestPoints
[1].X
= Gdiplus::REAL(rX
.getX());
2348 aDestPoints
[1].Y
= Gdiplus::REAL(rX
.getY());
2349 aDestPoints
[2].X
= Gdiplus::REAL(rY
.getX());
2350 aDestPoints
[2].Y
= Gdiplus::REAL(rY
.getY());
2352 aAttributes
.SetWrapMode(Gdiplus::WrapModeTileFlipXY
);
2354 aGraphics
.DrawImage(
2360 Gdiplus::REAL(nSrcWidth
),
2361 Gdiplus::REAL(nSrcHeight
),
2375 bool WinSalGraphicsImpl::drawGradient(const tools::PolyPolygon
& /*rPolygon*/,
2376 const Gradient
& /*rGradient*/)
2381 bool WinSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey
& /*rControlCacheKey*/, int /*nX*/, int /*nY*/)
2386 bool WinSalGraphicsImpl::RenderAndCacheNativeControl(OpenGLCompatibleDC
& /*rWhite*/, OpenGLCompatibleDC
& /*rBlack*/,
2387 int /*nX*/, int /*nY*/ , ControlCacheKey
& /*aControlCacheKey*/)
2392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */