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"
25 #include <rtl/strbuf.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/poly.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <basegfx/polygon/b2dpolygontools.hxx>
30 #include <basegfx/polygon/b2dpolypolygontools.hxx>
31 #include <win/wincomp.hxx>
32 #include <win/saldata.hxx>
33 #include <win/salgdi.h>
34 #include "win/salbmp.h"
35 #include <vcl/salbtype.hxx>
36 #include <win/salframe.h>
37 #include <basegfx/matrix/b2dhommatrixtools.hxx>
39 #include "outdata.hxx"
40 #include "win/salids.hrc"
44 #define min(a,b) (((a) < (b)) ? (a) : (b))
47 #define max(a,b) (((a) > (b)) ? (a) : (b))
60 #include <gdiplusenums.h>
61 #include <gdipluscolor.h>
65 #define SAL_POLYPOLYCOUNT_STACKBUF 8
66 #define SAL_POLYPOLYPOINTS_STACKBUF 64
68 #define DITHER_PAL_DELTA 51
69 #define DITHER_MAX_SYSCOLOR 16
70 #define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
72 #define SAL_POLY_STACKBUF 32
76 // #100127# draw an array of points which might also contain bezier control points
77 void ImplRenderPath( HDC hdc
, sal_uLong nPoints
, const SalPoint
* pPtAry
, const PolyFlags
* pFlgAry
)
82 // TODO: profile whether the following options are faster:
83 // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
84 // b) convert our flag array to window's and use PolyDraw
86 MoveToEx( hdc
, pPtAry
->mnX
, pPtAry
->mnY
, nullptr );
89 for( i
=1; i
<nPoints
; ++i
, ++pPtAry
, ++pFlgAry
)
91 if( *pFlgAry
!= PolyFlags::Control
)
93 LineTo( hdc
, pPtAry
->mnX
, pPtAry
->mnY
);
95 else if( nPoints
- i
> 2 )
97 PolyBezierTo( hdc
, reinterpret_cast<const POINT
*>(pPtAry
), 3 );
98 i
+= 2; pPtAry
+= 2; pFlgAry
+= 2;
104 // #100127# Fill point and flag memory from array of points which
105 // might also contain bezier control points for the PolyDraw() GDI method
106 // Make sure pWinPointAry and pWinFlagAry are big enough
107 void ImplPreparePolyDraw( bool bCloseFigures
,
109 const sal_uInt32
* pPoints
,
110 const SalPoint
* const* pPtAry
,
111 const PolyFlags
* const* pFlgAry
,
116 for( nCurrPoly
=0; nCurrPoly
<nPoly
; ++nCurrPoly
)
118 const POINT
* pCurrPoint
= reinterpret_cast<const POINT
*>( *pPtAry
++ );
119 const PolyFlags
* pCurrFlag
= *pFlgAry
++;
120 const sal_uInt32 nCurrPoints
= *pPoints
++;
121 const bool bHaveFlagArray( pCurrFlag
);
122 sal_uLong nCurrPoint
;
127 *pWinPointAry
++ = *pCurrPoint
++;
128 *pWinFlagAry
++ = PT_MOVETO
;
131 for( nCurrPoint
=1; nCurrPoint
<nCurrPoints
; )
133 // #102067# Check existence of flag array
134 if( bHaveFlagArray
&&
135 ( nCurrPoint
+ 2 ) < nCurrPoints
)
137 PolyFlags
P4( pCurrFlag
[ 2 ] );
139 if( ( PolyFlags::Control
== pCurrFlag
[ 0 ] ) &&
140 ( PolyFlags::Control
== pCurrFlag
[ 1 ] ) &&
141 ( PolyFlags::Normal
== P4
|| PolyFlags::Smooth
== P4
|| PolyFlags::Symmetric
== P4
) )
144 *pWinPointAry
++ = *pCurrPoint
++;
145 *pWinFlagAry
++ = PT_BEZIERTO
;
148 *pWinPointAry
++ = *pCurrPoint
++;
149 *pWinFlagAry
++ = PT_BEZIERTO
;
152 *pWinPointAry
++ = *pCurrPoint
++;
153 *pWinFlagAry
++ = PT_BEZIERTO
;
161 // regular line point
162 *pWinPointAry
++ = *pCurrPoint
++;
163 *pWinFlagAry
++ = PT_LINETO
;
170 pWinFlagAry
[-1] |= PT_CLOSEFIGURE
;
176 static PALETTEENTRY aImplSalSysPalEntryAry
[ DITHER_MAX_SYSCOLOR
] =
181 { 0, 0x80, 0x80, 0 },
183 { 0x80, 0, 0x80, 0 },
184 { 0x80, 0x80, 0, 0 },
185 { 0x80, 0x80, 0x80, 0 },
186 { 0xC0, 0xC0, 0xC0, 0 },
189 { 0, 0xFF, 0xFF, 0 },
191 { 0xFF, 0, 0xFF, 0 },
192 { 0xFF, 0xFF, 0, 0 },
193 { 0xFF, 0xFF, 0xFF, 0 }
196 static PALETTEENTRY aImplExtraColor1
=
201 static BYTE aOrdDither8Bit
[8][8] =
203 { 0, 38, 9, 48, 2, 40, 12, 50 },
204 { 25, 12, 35, 22, 28, 15, 37, 24 },
205 { 6, 44, 3, 41, 8, 47, 5, 44 },
206 { 32, 19, 28, 16, 34, 21, 31, 18 },
207 { 1, 40, 11, 49, 0, 39, 10, 48 },
208 { 27, 14, 36, 24, 26, 13, 36, 23 },
209 { 8, 46, 4, 43, 7, 45, 4, 42 },
210 { 33, 20, 30, 17, 32, 20, 29, 16 }
213 static BYTE aOrdDither16Bit
[8][8] =
215 { 0, 6, 1, 7, 0, 6, 1, 7 },
216 { 4, 2, 5, 3, 4, 2, 5, 3 },
217 { 1, 7, 0, 6, 1, 7, 0, 6 },
218 { 5, 3, 4, 2, 5, 3, 4, 2 },
219 { 0, 6, 1, 7, 0, 6, 1, 7 },
220 { 4, 2, 5, 3, 4, 2, 5, 3 },
221 { 1, 7, 0, 6, 1, 7, 0, 6 },
222 { 5, 3, 4, 2, 5, 3, 4, 2 }
225 SalColor
ImplGetROPSalColor( SalROPColor nROPColor
)
228 if ( nROPColor
== SalROPColor::N0
)
229 nSalColor
= MAKE_SALCOLOR( 0, 0, 0 );
231 nSalColor
= MAKE_SALCOLOR( 255, 255, 255 );
235 int ImplIsPaletteEntry( BYTE nRed
, BYTE nGreen
, BYTE nBlue
)
238 if ( !(nRed
% DITHER_PAL_DELTA
) && !(nGreen
% DITHER_PAL_DELTA
) && !(nBlue
% DITHER_PAL_DELTA
) )
241 PALETTEENTRY
* pPalEntry
= aImplSalSysPalEntryAry
;
243 // standard palette color?
244 for ( sal_uInt16 i
= 0; i
< DITHER_MAX_SYSCOLOR
; i
++, pPalEntry
++ )
246 if( pPalEntry
->peRed
== nRed
&& pPalEntry
->peGreen
== nGreen
&& pPalEntry
->peBlue
== nBlue
)
251 if ( aImplExtraColor1
.peRed
== nRed
&&
252 aImplExtraColor1
.peGreen
== nGreen
&&
253 aImplExtraColor1
.peBlue
== nBlue
)
263 WinSalGraphicsImpl::WinSalGraphicsImpl(WinSalGraphics
& rParent
):
275 WinSalGraphicsImpl::~WinSalGraphicsImpl()
286 DeleteBrush( mhBrush
);
291 void WinSalGraphicsImpl::Init()
295 void WinSalGraphicsImpl::freeResources()
299 bool WinSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uLong
)
304 void WinSalGraphicsImpl::copyBits( const SalTwoRect
& rPosAry
, SalGraphics
* pSrcGraphics
)
310 hSrcDC
= static_cast<WinSalGraphics
*>(pSrcGraphics
)->getHDC();
312 hSrcDC
= mrParent
.getHDC();
319 if ( (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
320 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
) )
322 BitBlt( mrParent
.getHDC(),
323 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
324 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
326 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
331 int nOldStretchMode
= SetStretchBltMode( mrParent
.getHDC(), STRETCH_DELETESCANS
);
332 StretchBlt( mrParent
.getHDC(),
333 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
334 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
336 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
337 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
339 SetStretchBltMode( mrParent
.getHDC(), nOldStretchMode
);
343 void ImplCalcOutSideRgn( const RECT
& rSrcRect
,
344 int nLeft
, int nTop
, int nRight
, int nBottom
,
345 HRGN
& rhInvalidateRgn
)
349 // calculate area outside the visible region
350 if ( rSrcRect
.left
< nLeft
)
352 if ( !rhInvalidateRgn
)
353 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
354 hTempRgn
= CreateRectRgn( -31999, 0, nLeft
, 31999 );
355 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
356 DeleteRegion( hTempRgn
);
358 if ( rSrcRect
.top
< nTop
)
360 if ( !rhInvalidateRgn
)
361 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
362 hTempRgn
= CreateRectRgn( 0, -31999, 31999, nTop
);
363 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
364 DeleteRegion( hTempRgn
);
366 if ( rSrcRect
.right
> nRight
)
368 if ( !rhInvalidateRgn
)
369 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
370 hTempRgn
= CreateRectRgn( nRight
, 0, 31999, 31999 );
371 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
372 DeleteRegion( hTempRgn
);
374 if ( rSrcRect
.bottom
> nBottom
)
376 if ( !rhInvalidateRgn
)
377 rhInvalidateRgn
= CreateRectRgnIndirect( &rSrcRect
);
378 hTempRgn
= CreateRectRgn( 0, nBottom
, 31999, 31999 );
379 CombineRgn( rhInvalidateRgn
, rhInvalidateRgn
, hTempRgn
, RGN_DIFF
);
380 DeleteRegion( hTempRgn
);
384 void WinSalGraphicsImpl::copyArea( long nDestX
, long nDestY
,
385 long nSrcX
, long nSrcY
,
386 long nSrcWidth
, long nSrcHeight
,
387 bool bWindowInvalidate
)
389 bool bRestoreClipRgn
= false;
390 HRGN hOldClipRgn
= nullptr;
391 int nOldClipRgnType
= ERROR
;
392 HRGN hInvalidateRgn
= nullptr;
394 // do we have to invalidate also the overlapping regions?
395 if ( bWindowInvalidate
&& mrParent
.isWindow() )
397 // compute and invalidate those parts that were either off-screen or covered by other windows
398 // while performing the above BitBlt
399 // those regions then have to be invalidated as they contain useless/wrong data
407 // restrict srcRect to this window (calc intersection)
408 aSrcRect
.left
= (int)nSrcX
;
409 aSrcRect
.top
= (int)nSrcY
;
410 aSrcRect
.right
= aSrcRect
.left
+(int)nSrcWidth
;
411 aSrcRect
.bottom
= aSrcRect
.top
+(int)nSrcHeight
;
412 GetClientRect( mrParent
.gethWnd(), &aClipRect
);
413 if ( IntersectRect( &aSrcRect
, &aSrcRect
, &aClipRect
) )
415 // transform srcRect to screen coordinates
419 ClientToScreen( mrParent
.gethWnd(), &aPt
);
420 aSrcRect
.left
+= aPt
.x
;
421 aSrcRect
.top
+= aPt
.y
;
422 aSrcRect
.right
+= aPt
.x
;
423 aSrcRect
.bottom
+= aPt
.y
;
424 hInvalidateRgn
= nullptr;
426 // compute the parts that are off screen (ie invisible)
428 ImplSalGetWorkArea( nullptr, &theScreen
, nullptr ); // find the screen area taking multiple monitors into account
429 ImplCalcOutSideRgn( aSrcRect
, theScreen
.left
, theScreen
.top
, theScreen
.right
, theScreen
.bottom
, hInvalidateRgn
);
431 // calculate regions that are covered by other windows
432 HRGN hTempRgn2
= nullptr;
433 HWND hWndTopWindow
= mrParent
.gethWnd();
434 // Find the TopLevel Window, because only Windows which are in
435 // in the foreground of our TopLevel window must be considered
436 if ( GetWindowStyle( hWndTopWindow
) & WS_CHILD
)
438 RECT aTempRect3
= aSrcRect
;
441 hWndTopWindow
= ::GetParent( hWndTopWindow
);
443 // Test if the Parent clips our window
444 GetClientRect( hWndTopWindow
, &aTempRect
);
448 ClientToScreen( hWndTopWindow
, &aPt2
);
449 aTempRect
.left
+= aPt2
.x
;
450 aTempRect
.top
+= aPt2
.y
;
451 aTempRect
.right
+= aPt2
.x
;
452 aTempRect
.bottom
+= aPt2
.y
;
453 IntersectRect( &aTempRect3
, &aTempRect3
, &aTempRect
);
455 while ( GetWindowStyle( hWndTopWindow
) & WS_CHILD
);
457 // If one or more Parents clip our window, than we must
458 // calculate the outside area
459 if ( !EqualRect( &aSrcRect
, &aTempRect3
) )
461 ImplCalcOutSideRgn( aSrcRect
,
462 aTempRect3
.left
, aTempRect3
.top
,
463 aTempRect3
.right
, aTempRect3
.bottom
,
467 // retrieve the top-most (z-order) child window
468 hWnd
= GetWindow( GetDesktopWindow(), GW_CHILD
);
471 if ( hWnd
== hWndTopWindow
)
473 if ( IsWindowVisible( hWnd
) && !IsIconic( hWnd
) )
475 GetWindowRect( hWnd
, &aTempRect
);
476 if ( IntersectRect( &aTempRect2
, &aSrcRect
, &aTempRect
) )
478 // hWnd covers part or all of aSrcRect
479 if ( !hInvalidateRgn
)
480 hInvalidateRgn
= CreateRectRgnIndirect( &aSrcRect
);
482 // get full bounding box of hWnd
483 hTempRgn
= CreateRectRgnIndirect( &aTempRect
);
485 // get region of hWnd (the window may be shaped)
487 hTempRgn2
= CreateRectRgn( 0, 0, 0, 0 );
488 int nRgnType
= GetWindowRgn( hWnd
, hTempRgn2
);
489 if ( (nRgnType
!= ERROR
) && (nRgnType
!= NULLREGION
) )
491 // convert window region to screen coordinates
492 OffsetRgn( hTempRgn2
, aTempRect
.left
, aTempRect
.top
);
493 // and intersect with the window's bounding box
494 CombineRgn( hTempRgn
, hTempRgn
, hTempRgn2
, RGN_AND
);
496 // finally compute that part of aSrcRect which is not covered by any parts of hWnd
497 CombineRgn( hInvalidateRgn
, hInvalidateRgn
, hTempRgn
, RGN_DIFF
);
498 DeleteRegion( hTempRgn
);
501 // retrieve the next window in the z-order, i.e. the window below hwnd
502 hWnd
= GetWindow( hWnd
, GW_HWNDNEXT
);
505 DeleteRegion( hTempRgn2
);
506 if ( hInvalidateRgn
)
508 // hInvalidateRgn contains the fully visible parts of the original srcRect
509 hTempRgn
= CreateRectRgnIndirect( &aSrcRect
);
510 // subtract it from the original rect to get the occluded parts
511 int nRgnType
= CombineRgn( hInvalidateRgn
, hTempRgn
, hInvalidateRgn
, RGN_DIFF
);
512 DeleteRegion( hTempRgn
);
514 if ( (nRgnType
!= ERROR
) && (nRgnType
!= NULLREGION
) )
516 // move the occluded parts to the destination pos
517 int nOffX
= (int)(nDestX
-nSrcX
);
518 int nOffY
= (int)(nDestY
-nSrcY
);
519 OffsetRgn( hInvalidateRgn
, nOffX
-aPt
.x
, nOffY
-aPt
.y
);
521 // by excluding hInvalidateRgn from the system's clip region
522 // we will prevent bitblt from copying useless data
523 // especially now shadows from overlapping windows will appear (#i36344)
524 hOldClipRgn
= CreateRectRgn( 0, 0, 0, 0 );
525 nOldClipRgnType
= GetClipRgn( mrParent
.getHDC(), hOldClipRgn
);
527 bRestoreClipRgn
= TRUE
; // indicate changed clipregion and force invalidate
528 ExtSelectClipRgn( mrParent
.getHDC(), hInvalidateRgn
, RGN_DIFF
);
534 BitBlt( mrParent
.getHDC(),
535 (int)nDestX
, (int)nDestY
,
536 (int)nSrcWidth
, (int)nSrcHeight
,
538 (int)nSrcX
, (int)nSrcY
,
541 if( bRestoreClipRgn
)
543 // restore old clip region
544 if( nOldClipRgnType
!= ERROR
)
545 SelectClipRgn( mrParent
.getHDC(), hOldClipRgn
);
546 DeleteRegion( hOldClipRgn
);
548 // invalidate regions that were not copied
549 bool bInvalidate
= true;
551 // Combine Invalidate vcl::Region with existing ClipRegion
552 HRGN hTempRgn
= CreateRectRgn( 0, 0, 0, 0 );
553 if ( GetClipRgn( mrParent
.getHDC(), hTempRgn
) == 1 )
555 int nRgnType
= CombineRgn( hInvalidateRgn
, hTempRgn
, hInvalidateRgn
, RGN_AND
);
556 if ( (nRgnType
== ERROR
) || (nRgnType
== NULLREGION
) )
559 DeleteRegion( hTempRgn
);
563 InvalidateRgn( mrParent
.gethWnd(), hInvalidateRgn
, TRUE
);
564 // here we only initiate an update if this is the MainThread,
565 // so that there is no deadlock when handling the Paint event,
566 // as the SolarMutex is already held by this Thread
567 SalData
* pSalData
= GetSalData();
568 DWORD nCurThreadId
= GetCurrentThreadId();
569 if ( pSalData
->mnAppThreadId
== nCurThreadId
)
570 UpdateWindow( mrParent
.gethWnd() );
573 DeleteRegion( hInvalidateRgn
);
580 void ImplDrawBitmap( HDC hDC
, const SalTwoRect
& rPosAry
, const WinSalBitmap
& rSalBitmap
,
581 bool bPrinter
, int nDrawMode
)
586 HBITMAP hDrawDDB
= rSalBitmap
.ImplGethDDB();
587 WinSalBitmap
* pTmpSalBmp
= nullptr;
588 bool bPrintDDB
= ( bPrinter
&& hDrawDDB
);
592 pTmpSalBmp
= new WinSalBitmap
;
593 pTmpSalBmp
->Create( rSalBitmap
, rSalBitmap
.GetBitCount() );
594 hDrawDIB
= pTmpSalBmp
->ImplGethDIB();
597 hDrawDIB
= rSalBitmap
.ImplGethDIB();
601 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( hDrawDIB
));
602 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
603 WinSalBitmap::ImplGetDIBColorCount( hDrawDIB
) * sizeof( RGBQUAD
);
604 const int nOldStretchMode
= SetStretchBltMode( hDC
, STRETCH_DELETESCANS
);
607 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
608 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
609 (int)rPosAry
.mnSrcX
, (int)(pBI
->bmiHeader
.biHeight
- rPosAry
.mnSrcHeight
- rPosAry
.mnSrcY
),
610 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
611 pBits
, pBI
, DIB_RGB_COLORS
, nDrawMode
);
613 GlobalUnlock( hDrawDIB
);
614 SetStretchBltMode( hDC
, nOldStretchMode
);
616 else if( hDrawDDB
&& !bPrintDDB
)
618 HDC hBmpDC
= ImplGetCachedDC( CACHED_HDC_DRAW
, hDrawDDB
);
619 COLORREF nOldBkColor
= RGB(0xFF,0xFF,0xFF);
620 COLORREF nOldTextColor
= RGB(0,0,0);
621 bool bMono
= ( rSalBitmap
.GetBitCount() == 1 );
625 COLORREF nBkColor
= RGB( 0xFF, 0xFF, 0xFF );
626 COLORREF nTextColor
= RGB( 0x00, 0x00, 0x00 );
627 //fdo#33455 handle 1 bit depth pngs with palette entries
628 //to set fore/back colors
629 if (BitmapBuffer
* pBitmapBuffer
= const_cast<WinSalBitmap
&>(rSalBitmap
).AcquireBuffer(BitmapAccessMode::Info
))
631 const BitmapPalette
& rPalette
= pBitmapBuffer
->maPalette
;
632 if (rPalette
.GetEntryCount() == 2)
635 nCol
= ImplColorToSal(rPalette
[0]);
636 nTextColor
= RGB( SALCOLOR_RED(nCol
), SALCOLOR_GREEN(nCol
), SALCOLOR_BLUE(nCol
) );
637 nCol
= ImplColorToSal(rPalette
[1]);
638 nBkColor
= RGB( SALCOLOR_RED(nCol
), SALCOLOR_GREEN(nCol
), SALCOLOR_BLUE(nCol
) );
640 const_cast<WinSalBitmap
&>(rSalBitmap
).ReleaseBuffer(pBitmapBuffer
, BitmapAccessMode::Info
);
642 nOldBkColor
= SetBkColor( hDC
, nBkColor
);
643 nOldTextColor
= ::SetTextColor( hDC
, nTextColor
);
646 if ( (rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
) &&
647 (rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
) )
650 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
651 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
653 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
658 const int nOldStretchMode
= SetStretchBltMode( hDC
, STRETCH_DELETESCANS
);
661 (int)rPosAry
.mnDestX
, (int)rPosAry
.mnDestY
,
662 (int)rPosAry
.mnDestWidth
, (int)rPosAry
.mnDestHeight
,
664 (int)rPosAry
.mnSrcX
, (int)rPosAry
.mnSrcY
,
665 (int)rPosAry
.mnSrcWidth
, (int)rPosAry
.mnSrcHeight
,
668 SetStretchBltMode( hDC
, nOldStretchMode
);
673 SetBkColor( hDC
, nOldBkColor
);
674 ::SetTextColor( hDC
, nOldTextColor
);
677 ImplReleaseCachedDC( CACHED_HDC_DRAW
);
687 void WinSalGraphicsImpl::drawBitmap(const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
)
689 bool bTryDirectPaint(!mrParent
.isPrinter() && !mbXORMode
);
693 // only paint direct when no scaling and no MapMode, else the
694 // more expensive conversions may be done for short-time Bitmap/BitmapEx
695 // used for buffering only
696 if(rPosAry
.mnSrcWidth
== rPosAry
.mnDestWidth
&& rPosAry
.mnSrcHeight
== rPosAry
.mnDestHeight
)
698 bTryDirectPaint
= false;
702 // try to draw using GdiPlus directly
703 if(bTryDirectPaint
&& tryDrawBitmapGdiPlus(rPosAry
, rSalBitmap
))
708 // fall back old stuff
709 assert(dynamic_cast<const WinSalBitmap
*>(&rSalBitmap
));
711 ImplDrawBitmap(mrParent
.getHDC(), rPosAry
, static_cast<const WinSalBitmap
&>(rSalBitmap
),
712 mrParent
.isPrinter(),
713 mbXORMode
? SRCINVERT
: SRCCOPY
);
716 void WinSalGraphicsImpl::drawBitmap( const SalTwoRect
& rPosAry
,
717 const SalBitmap
& rSSalBitmap
,
718 const SalBitmap
& rSTransparentBitmap
)
720 SAL_WARN_IF( mrParent
.isPrinter(), "vcl", "No transparency print possible!" );
721 bool bTryDirectPaint(!mrParent
.isPrinter() && !mbXORMode
);
723 // try to draw using GdiPlus directly
724 if(bTryDirectPaint
&& drawAlphaBitmap(rPosAry
, rSSalBitmap
, rSTransparentBitmap
))
729 assert(dynamic_cast<const WinSalBitmap
*>(&rSSalBitmap
));
730 assert(dynamic_cast<const WinSalBitmap
*>(&rSTransparentBitmap
));
732 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
733 const WinSalBitmap
& rTransparentBitmap
= static_cast<const WinSalBitmap
&>(rSTransparentBitmap
);
735 SalTwoRect aPosAry
= rPosAry
;
736 int nDstX
= (int)aPosAry
.mnDestX
;
737 int nDstY
= (int)aPosAry
.mnDestY
;
738 int nDstWidth
= (int)aPosAry
.mnDestWidth
;
739 int nDstHeight
= (int)aPosAry
.mnDestHeight
;
740 HDC hDC
= mrParent
.getHDC();
741 HBITMAP hMemBitmap
= nullptr;
742 HBITMAP hMaskBitmap
= nullptr;
744 if( ( nDstWidth
> CACHED_HDC_DEFEXT
) || ( nDstHeight
> CACHED_HDC_DEFEXT
) )
746 hMemBitmap
= CreateCompatibleBitmap( hDC
, nDstWidth
, nDstHeight
);
747 hMaskBitmap
= CreateCompatibleBitmap( hDC
, nDstWidth
, nDstHeight
);
750 HDC hMemDC
= ImplGetCachedDC( CACHED_HDC_1
, hMemBitmap
);
751 HDC hMaskDC
= ImplGetCachedDC( CACHED_HDC_2
, hMaskBitmap
);
753 aPosAry
.mnDestX
= aPosAry
.mnDestY
= 0;
754 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hDC
, nDstX
, nDstY
, SRCCOPY
);
756 // WIN/WNT seems to have a minor problem mapping the correct color of the
757 // mask to the palette if we draw the DIB directly ==> draw DDB
758 if( ( GetBitCount() <= 8 ) && rTransparentBitmap
.ImplGethDIB() && rTransparentBitmap
.GetBitCount() == 1 )
762 if( aTmp
.Create( rTransparentBitmap
, &mrParent
) )
763 ImplDrawBitmap( hMaskDC
, aPosAry
, aTmp
, false, SRCCOPY
);
766 ImplDrawBitmap( hMaskDC
, aPosAry
, rTransparentBitmap
, false, SRCCOPY
);
768 // now MemDC contains background, MaskDC the transparency mask
770 // #105055# Respect XOR mode
773 ImplDrawBitmap( hMaskDC
, aPosAry
, rSalBitmap
, false, SRCERASE
);
774 // now MaskDC contains the bitmap area with black background
775 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCINVERT
);
776 // now MemDC contains background XORed bitmap area ontop
780 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCAND
);
781 // now MemDC contains background with masked-out bitmap area
782 ImplDrawBitmap( hMaskDC
, aPosAry
, rSalBitmap
, false, SRCERASE
);
783 // now MaskDC contains the bitmap area with black background
784 BitBlt( hMemDC
, 0, 0, nDstWidth
, nDstHeight
, hMaskDC
, 0, 0, SRCPAINT
);
785 // now MemDC contains background and bitmap merged together
788 BitBlt( hDC
, nDstX
, nDstY
, nDstWidth
, nDstHeight
, hMemDC
, 0, 0, SRCCOPY
);
790 ImplReleaseCachedDC( CACHED_HDC_1
);
791 ImplReleaseCachedDC( CACHED_HDC_2
);
793 // hMemBitmap != 0 ==> hMaskBitmap != 0
796 DeleteObject( hMemBitmap
);
797 DeleteObject( hMaskBitmap
);
801 bool WinSalGraphicsImpl::drawAlphaRect( long nX
, long nY
, long nWidth
,
802 long nHeight
, sal_uInt8 nTransparency
)
804 if( mbPen
|| !mbBrush
|| mbXORMode
)
805 return false; // can only perform solid fills without XOR.
807 HDC hMemDC
= ImplGetCachedDC( CACHED_HDC_1
);
808 SetPixel( hMemDC
, (int)0, (int)0, mnBrushColor
);
810 BLENDFUNCTION aFunc
= {
813 sal::static_int_cast
<sal_uInt8
>(255 - 255L*nTransparency
/100),
817 // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
819 bool bRet
= GdiAlphaBlend(mrParent
.getHDC(), nX
, nY
, nWidth
, nHeight
,
823 ImplReleaseCachedDC( CACHED_HDC_1
);
828 void WinSalGraphicsImpl::drawMask( const SalTwoRect
& rPosAry
,
829 const SalBitmap
& rSSalBitmap
,
830 SalColor nMaskColor
)
832 SAL_WARN_IF( mrParent
.isPrinter(), "vcl", "No transparency print possible!" );
834 assert(dynamic_cast<const WinSalBitmap
*>(&rSSalBitmap
));
836 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
838 SalTwoRect aPosAry
= rPosAry
;
839 const BYTE cRed
= SALCOLOR_RED( nMaskColor
);
840 const BYTE cGreen
= SALCOLOR_GREEN( nMaskColor
);
841 const BYTE cBlue
= SALCOLOR_BLUE( nMaskColor
);
842 HDC hDC
= mrParent
.getHDC();
843 HBRUSH hMaskBrush
= CreateSolidBrush( RGB( cRed
, cGreen
, cBlue
) );
844 HBRUSH hOldBrush
= SelectBrush( hDC
, hMaskBrush
);
846 // WIN/WNT seems to have a minor problem mapping the correct color of the
847 // mask to the palette if we draw the DIB directly ==> draw DDB
848 if( ( GetBitCount() <= 8 ) && rSalBitmap
.ImplGethDIB() && rSalBitmap
.GetBitCount() == 1 )
852 if( aTmp
.Create( rSalBitmap
, &mrParent
) )
853 ImplDrawBitmap( hDC
, aPosAry
, aTmp
, false, 0x00B8074AUL
);
856 ImplDrawBitmap( hDC
, aPosAry
, rSalBitmap
, false, 0x00B8074AUL
);
858 SelectBrush( hDC
, hOldBrush
);
859 DeleteBrush( hMaskBrush
);
862 SalBitmap
* WinSalGraphicsImpl::getBitmap( long nX
, long nY
, long nDX
, long nDY
)
864 SAL_WARN_IF( mrParent
.isPrinter(), "vcl", "No ::GetBitmap() from printer possible!" );
866 WinSalBitmap
* pSalBitmap
= nullptr;
871 HDC hDC
= mrParent
.getHDC();
872 HBITMAP hBmpBitmap
= CreateCompatibleBitmap( hDC
, nDX
, nDY
);
873 HDC hBmpDC
= ImplGetCachedDC( CACHED_HDC_1
, hBmpBitmap
);
876 bRet
= BitBlt( hBmpDC
, 0, 0, (int) nDX
, (int) nDY
, hDC
, (int) nX
, (int) nY
, SRCCOPY
) ? TRUE
: FALSE
;
877 ImplReleaseCachedDC( CACHED_HDC_1
);
881 pSalBitmap
= new WinSalBitmap
;
883 if( !pSalBitmap
->Create( hBmpBitmap
, FALSE
, FALSE
) )
886 pSalBitmap
= nullptr;
891 // #124826# avoid resource leak! Happens when running without desktop access (remote desktop, service, may be screensavers)
892 DeleteBitmap( hBmpBitmap
);
898 SalColor
WinSalGraphicsImpl::getPixel( long nX
, long nY
)
900 COLORREF aWinCol
= ::GetPixel( mrParent
.getHDC(), (int) nX
, (int) nY
);
902 if ( CLR_INVALID
== aWinCol
)
903 return MAKE_SALCOLOR( 0, 0, 0 );
905 return MAKE_SALCOLOR( GetRValue( aWinCol
),
906 GetGValue( aWinCol
),
907 GetBValue( aWinCol
) );
910 void WinSalGraphicsImpl::invert( long nX
, long nY
, long nWidth
, long nHeight
, SalInvert nFlags
)
912 if ( nFlags
& SalInvert::TrackFrame
)
914 HPEN hDotPen
= CreatePen( PS_DOT
, 0, 0 );
915 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hDotPen
);
916 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), GetStockBrush( NULL_BRUSH
) );
917 int nOldROP
= SetROP2( mrParent
.getHDC(), R2_NOT
);
919 WIN_Rectangle( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)(nX
+nWidth
), (int)(nY
+nHeight
) );
921 SetROP2( mrParent
.getHDC(), nOldROP
);
922 SelectPen( mrParent
.getHDC(), hOldPen
);
923 SelectBrush( mrParent
.getHDC(), hOldBrush
);
924 DeletePen( hDotPen
);
926 else if ( nFlags
& SalInvert::N50
)
928 SalData
* pSalData
= GetSalData();
929 if ( !pSalData
->mh50Brush
)
931 if ( !pSalData
->mh50Bmp
)
932 pSalData
->mh50Bmp
= ImplLoadSalBitmap( SAL_RESID_BITMAP_50
);
933 pSalData
->mh50Brush
= CreatePatternBrush( pSalData
->mh50Bmp
);
936 COLORREF nOldTextColor
= ::SetTextColor( mrParent
.getHDC(), 0 );
937 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), pSalData
->mh50Brush
);
938 PatBlt( mrParent
.getHDC(), nX
, nY
, nWidth
, nHeight
, PATINVERT
);
939 ::SetTextColor( mrParent
.getHDC(), nOldTextColor
);
940 SelectBrush( mrParent
.getHDC(), hOldBrush
);
945 aRect
.left
= (int)nX
;
947 aRect
.right
= (int)nX
+nWidth
;
948 aRect
.bottom
= (int)nY
+nHeight
;
949 ::InvertRect( mrParent
.getHDC(), &aRect
);
953 void WinSalGraphicsImpl::invert( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, SalInvert nSalFlags
)
958 HBRUSH hOldBrush
= nullptr;
959 COLORREF nOldTextColor
RGB(0,0,0);
960 int nOldROP
= SetROP2( mrParent
.getHDC(), R2_NOT
);
962 if ( nSalFlags
& SalInvert::TrackFrame
)
963 hPen
= CreatePen( PS_DOT
, 0, 0 );
967 if ( nSalFlags
& SalInvert::N50
)
969 SalData
* pSalData
= GetSalData();
970 if ( !pSalData
->mh50Brush
)
972 if ( !pSalData
->mh50Bmp
)
973 pSalData
->mh50Bmp
= ImplLoadSalBitmap( SAL_RESID_BITMAP_50
);
974 pSalData
->mh50Brush
= CreatePatternBrush( pSalData
->mh50Bmp
);
977 hBrush
= pSalData
->mh50Brush
;
980 hBrush
= GetStockBrush( BLACK_BRUSH
);
982 hPen
= GetStockPen( NULL_PEN
);
983 nOldTextColor
= ::SetTextColor( mrParent
.getHDC(), 0 );
984 hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
986 hOldPen
= SelectPen( mrParent
.getHDC(), hPen
);
988 POINT
const * pWinPtAry
;
989 // for NT, we can handover the array directly
990 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
992 pWinPtAry
= reinterpret_cast<POINT
const *>(pPtAry
);
993 // for Windows 95 and its maximum number of points
994 if ( nSalFlags
& SalInvert::TrackFrame
)
996 if ( !Polyline( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
997 Polyline( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1001 if ( !Polygon( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1002 Polygon( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1005 SetROP2( mrParent
.getHDC(), nOldROP
);
1006 SelectPen( mrParent
.getHDC(), hOldPen
);
1008 if ( nSalFlags
& SalInvert::TrackFrame
)
1012 ::SetTextColor( mrParent
.getHDC(), nOldTextColor
);
1013 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1017 sal_uInt16
WinSalGraphicsImpl::GetBitCount() const
1019 return (sal_uInt16
)GetDeviceCaps( mrParent
.getHDC(), BITSPIXEL
);
1022 long WinSalGraphicsImpl::GetGraphicsWidth() const
1024 if( mrParent
.gethWnd() && IsWindow( mrParent
.gethWnd() ) )
1026 WinSalFrame
* pFrame
= GetWindowPtr( mrParent
.gethWnd() );
1029 if( pFrame
->maGeometry
.nWidth
)
1030 return pFrame
->maGeometry
.nWidth
;
1033 // TODO: perhaps not needed, maGeometry should always be up-to-date
1035 GetClientRect( mrParent
.gethWnd(), &aRect
);
1044 void WinSalGraphicsImpl::ResetClipRegion()
1046 if ( mrParent
.mhRegion
)
1048 DeleteRegion( mrParent
.mhRegion
);
1049 mrParent
.mhRegion
= nullptr;
1052 SelectClipRgn( mrParent
.getHDC(), nullptr );
1055 static bool containsOnlyHorizontalAndVerticalEdges(const basegfx::B2DPolygon
& rCandidate
)
1057 if(rCandidate
.areControlPointsUsed())
1062 const sal_uInt32
nPointCount(rCandidate
.count());
1069 const sal_uInt32
nEdgeCount(rCandidate
.isClosed() ? nPointCount
+ 1 : nPointCount
);
1070 basegfx::B2DPoint
aLast(rCandidate
.getB2DPoint(0));
1072 for(sal_uInt32
a(1); a
< nEdgeCount
; a
++)
1074 const sal_uInt32
nNextIndex(a
% nPointCount
);
1075 const basegfx::B2DPoint
aCurrent(rCandidate
.getB2DPoint(nNextIndex
));
1077 if(!basegfx::fTools::equal(aLast
.getX(), aCurrent
.getX()) && !basegfx::fTools::equal(aLast
.getY(), aCurrent
.getY()))
1088 static bool containsOnlyHorizontalAndVerticalEdges(const basegfx::B2DPolyPolygon
& rCandidate
)
1090 if(rCandidate
.areControlPointsUsed())
1095 for(sal_uInt32
a(0); a
< rCandidate
.count(); a
++)
1097 if(!containsOnlyHorizontalAndVerticalEdges(rCandidate
.getB2DPolygon(a
)))
1106 bool WinSalGraphicsImpl::setClipRegion( const vcl::Region
& i_rClip
)
1108 if ( mrParent
.mhRegion
)
1110 DeleteRegion( mrParent
.mhRegion
);
1111 mrParent
.mhRegion
= nullptr;
1114 bool bUsePolygon(i_rClip
.HasPolyPolygonOrB2DPolyPolygon());
1115 static bool bTryToAvoidPolygon(true);
1117 // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve
1118 // and only contains horizontal/vertical edges. In that case, use the fallback
1119 // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do
1120 // the correct polygon-to-RegionBand transformation.
1121 // Background is that when using the same Rectangle as rectangle or as Polygon
1122 // clip region will lead to different results; the polygon-based one will be
1123 // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This
1124 // again is because of the polygon-nature and it's classic handling when filling.
1125 // This also means that all cases which use a 'true' polygon-based incarnation of
1126 // a vcl::Region should know what they do - it may lead to repaint errors.
1127 if(bUsePolygon
&& bTryToAvoidPolygon
)
1129 const basegfx::B2DPolyPolygon
aPolyPolygon( i_rClip
.GetAsB2DPolyPolygon() );
1131 if(!aPolyPolygon
.areControlPointsUsed())
1133 if(containsOnlyHorizontalAndVerticalEdges(aPolyPolygon
))
1135 bUsePolygon
= false;
1142 // #i122149# check the comment above to know that this may lead to potential repaint
1143 // problems. It may be solved (if needed) by scaling the polygon by one in X
1144 // and Y. Currently the workaround to only use it if really unavoidable will
1145 // solve most cases. When someone is really using polygon-based Regions he
1146 // should know what he is doing.
1147 // Added code to do that scaling to check if it works, testing it.
1148 const basegfx::B2DPolyPolygon
aPolyPolygon( i_rClip
.GetAsB2DPolyPolygon() );
1149 const sal_uInt32
nCount(aPolyPolygon
.count());
1153 std::vector
< POINT
> aPolyPoints
;
1154 aPolyPoints
.reserve( 1024 );
1155 std::vector
< INT
> aPolyCounts( nCount
, 0 );
1156 basegfx::B2DHomMatrix aExpand
;
1157 sal_uInt32
nTargetCount(0);
1158 static bool bExpandByOneInXandY(true);
1160 if(bExpandByOneInXandY
)
1162 const basegfx::B2DRange
aRangeS(aPolyPolygon
.getB2DRange());
1163 const basegfx::B2DRange
aRangeT(aRangeS
.getMinimum(), aRangeS
.getMaximum() + basegfx::B2DTuple(1.0, 1.0));
1164 aExpand
= basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS
, aRangeT
));
1167 for(sal_uInt32
a(0); a
< nCount
; a
++)
1169 const basegfx::B2DPolygon
aPoly(
1170 basegfx::tools::adaptiveSubdivideByDistance(
1171 aPolyPolygon
.getB2DPolygon(a
),
1173 const sal_uInt32
nPoints(aPoly
.count());
1175 // tdf#40863 For CustomShapes there is a hack (see
1176 // f64ef72743e55389e446e0d4bc6febd475011023) that adds polygons
1177 // with a single point in top-left and bottom-right corner
1178 // of the BoundRect to be able to determine the correct BoundRect
1179 // in the slideshow. Unfortunately, CreatePolyPolygonRgn below
1180 // fails with polygons containing a single pixel, so clipping is
1181 // lost. For now, use only polygons with more than two points - the
1182 // ones that may have an area.
1183 // Note: polygons with one point which are curves may have an area,
1184 // but the polygon is already subdivided here, so no need to test
1188 aPolyCounts
[nTargetCount
] = nPoints
;
1191 for( sal_uInt32 b
= 0; b
< nPoints
; b
++ )
1193 basegfx::B2DPoint
aPt(aPoly
.getB2DPoint(b
));
1195 if(bExpandByOneInXandY
)
1197 aPt
= aExpand
* aPt
;
1201 // #i122149# do correct rounding
1202 aPOINT
.x
= basegfx::fround(aPt
.getX());
1203 aPOINT
.y
= basegfx::fround(aPt
.getY());
1204 aPolyPoints
.push_back( aPOINT
);
1211 mrParent
.mhRegion
= CreatePolyPolygonRgn( &aPolyPoints
[0], &aPolyCounts
[0], nTargetCount
, ALTERNATE
);
1217 RectangleVector aRectangles
;
1218 i_rClip
.GetRegionRectangles(aRectangles
);
1220 sal_uLong nRectBufSize
= sizeof(RECT
)*aRectangles
.size();
1221 if ( aRectangles
.size() < SAL_CLIPRECT_COUNT
)
1223 if ( !mrParent
.mpStdClipRgnData
)
1224 mrParent
.mpStdClipRgnData
= reinterpret_cast<RGNDATA
*>(new BYTE
[sizeof(RGNDATA
)-1+(SAL_CLIPRECT_COUNT
*sizeof(RECT
))]);
1225 mrParent
.mpClipRgnData
= mrParent
.mpStdClipRgnData
;
1228 mrParent
.mpClipRgnData
= reinterpret_cast<RGNDATA
*>(new BYTE
[sizeof(RGNDATA
)-1+nRectBufSize
]);
1229 mrParent
.mpClipRgnData
->rdh
.dwSize
= sizeof( RGNDATAHEADER
);
1230 mrParent
.mpClipRgnData
->rdh
.iType
= RDH_RECTANGLES
;
1231 mrParent
.mpClipRgnData
->rdh
.nCount
= aRectangles
.size();
1232 mrParent
.mpClipRgnData
->rdh
.nRgnSize
= nRectBufSize
;
1233 RECT
* pBoundRect
= &(mrParent
.mpClipRgnData
->rdh
.rcBound
);
1234 SetRectEmpty( pBoundRect
);
1235 RECT
* pNextClipRect
= reinterpret_cast<RECT
*>(&(mrParent
.mpClipRgnData
->Buffer
));
1236 bool bFirstClipRect
= true;
1238 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
1240 const long nW(aRectIter
->GetWidth());
1241 const long nH(aRectIter
->GetHeight());
1245 const long nRight(aRectIter
->Left() + nW
);
1246 const long nBottom(aRectIter
->Top() + nH
);
1250 pBoundRect
->left
= aRectIter
->Left();
1251 pBoundRect
->top
= aRectIter
->Top();
1252 pBoundRect
->right
= nRight
;
1253 pBoundRect
->bottom
= nBottom
;
1254 bFirstClipRect
= false;
1258 if(aRectIter
->Left() < pBoundRect
->left
)
1260 pBoundRect
->left
= (int)aRectIter
->Left();
1263 if(aRectIter
->Top() < pBoundRect
->top
)
1265 pBoundRect
->top
= (int)aRectIter
->Top();
1268 if(nRight
> pBoundRect
->right
)
1270 pBoundRect
->right
= (int)nRight
;
1273 if(nBottom
> pBoundRect
->bottom
)
1275 pBoundRect
->bottom
= (int)nBottom
;
1279 pNextClipRect
->left
= (int)aRectIter
->Left();
1280 pNextClipRect
->top
= (int)aRectIter
->Top();
1281 pNextClipRect
->right
= (int)nRight
;
1282 pNextClipRect
->bottom
= (int)nBottom
;
1287 mrParent
.mpClipRgnData
->rdh
.nCount
--;
1288 mrParent
.mpClipRgnData
->rdh
.nRgnSize
-= sizeof( RECT
);
1292 // create clip region from ClipRgnData
1293 if(0 == mrParent
.mpClipRgnData
->rdh
.nCount
)
1295 // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given
1296 // that contains no polygons or only empty ones (no width/height). This is
1297 // perfectly fine and we are done, except setting it (see end of method)
1299 else if(1 == mrParent
.mpClipRgnData
->rdh
.nCount
)
1301 RECT
* pRect
= &(mrParent
.mpClipRgnData
->rdh
.rcBound
);
1302 mrParent
.mhRegion
= CreateRectRgn( pRect
->left
, pRect
->top
,
1303 pRect
->right
, pRect
->bottom
);
1305 else if(mrParent
.mpClipRgnData
->rdh
.nCount
> 1)
1307 sal_uLong nSize
= mrParent
.mpClipRgnData
->rdh
.nRgnSize
+sizeof(RGNDATAHEADER
);
1308 mrParent
.mhRegion
= ExtCreateRegion( nullptr, nSize
, mrParent
.mpClipRgnData
);
1310 // if ExtCreateRegion(...) is not supported
1311 if( !mrParent
.mhRegion
)
1313 RGNDATAHEADER
const & pHeader
= mrParent
.mpClipRgnData
->rdh
;
1315 if( pHeader
.nCount
)
1317 RECT
* pRect
= reinterpret_cast<RECT
*>(mrParent
.mpClipRgnData
->Buffer
);
1318 mrParent
.mhRegion
= CreateRectRgn( pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1321 for( sal_uLong n
= 1; n
< pHeader
.nCount
; n
++, pRect
++ )
1323 HRGN hRgn
= CreateRectRgn( pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1324 CombineRgn( mrParent
.mhRegion
, mrParent
.mhRegion
, hRgn
, RGN_OR
);
1325 DeleteRegion( hRgn
);
1330 if ( mrParent
.mpClipRgnData
!= mrParent
.mpStdClipRgnData
)
1331 delete [] reinterpret_cast<BYTE
*>(mrParent
.mpClipRgnData
);
1335 if( mrParent
.mhRegion
)
1337 SelectClipRgn( mrParent
.getHDC(), mrParent
.mhRegion
);
1339 // debug code if you want to check range of the newly applied ClipRegion
1341 //const int aRegionType = GetRgnBox(mrParent.mhRegion, &aBound);
1347 // #i123585# See above, this is a valid case, execute it
1348 SelectClipRgn( mrParent
.getHDC(), nullptr );
1351 // #i123585# retval no longer dependent of mrParent.mhRegion, see TaskId comments above
1355 void WinSalGraphicsImpl::SetLineColor()
1357 // create and select new pen
1358 HPEN hNewPen
= GetStockPen( NULL_PEN
);
1359 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hNewPen
);
1361 // destroy or save old pen
1368 mrParent
.mhDefPen
= hOldPen
;
1376 void WinSalGraphicsImpl::SetLineColor( SalColor nSalColor
)
1378 maLineColor
= nSalColor
;
1379 COLORREF nPenColor
= PALETTERGB( SALCOLOR_RED( nSalColor
),
1380 SALCOLOR_GREEN( nSalColor
),
1381 SALCOLOR_BLUE( nSalColor
) );
1382 HPEN hNewPen
= nullptr;
1383 bool bStockPen
= FALSE
;
1385 // search for stock pen (only screen, because printer have problems,
1386 // when we use stock objects)
1387 if ( !mrParent
.isPrinter() )
1389 SalData
* pSalData
= GetSalData();
1390 for ( sal_uInt16 i
= 0; i
< pSalData
->mnStockPenCount
; i
++ )
1392 if ( nPenColor
== pSalData
->maStockPenColorAry
[i
] )
1394 hNewPen
= pSalData
->mhStockPenAry
[i
];
1404 if ( !mrParent
.isPrinter() )
1406 if ( GetSalData()->mhDitherPal
&& ImplIsSysColorEntry( nSalColor
) )
1407 nPenColor
= PALRGB_TO_RGB( nPenColor
);
1410 hNewPen
= CreatePen( PS_SOLID
, mrParent
.mnPenWidth
, nPenColor
);
1415 HPEN hOldPen
= SelectPen( mrParent
.getHDC(), hNewPen
);
1417 // destroy or save old pen
1424 mrParent
.mhDefPen
= hOldPen
;
1427 mnPenColor
= nPenColor
;
1430 mbStockPen
= bStockPen
;
1433 void WinSalGraphicsImpl::SetFillColor()
1435 // create and select new brush
1436 HBRUSH hNewBrush
= GetStockBrush( NULL_BRUSH
);
1437 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hNewBrush
);
1439 // destroy or save old brush
1442 if ( !mbStockBrush
)
1443 DeleteBrush( mhBrush
);
1446 mrParent
.mhDefBrush
= hOldBrush
;
1449 mhBrush
= hNewBrush
;
1451 mbStockBrush
= TRUE
;
1454 void WinSalGraphicsImpl::SetFillColor( SalColor nSalColor
)
1456 maFillColor
= nSalColor
;
1457 SalData
* pSalData
= GetSalData();
1458 BYTE nRed
= SALCOLOR_RED( nSalColor
);
1459 BYTE nGreen
= SALCOLOR_GREEN( nSalColor
);
1460 BYTE nBlue
= SALCOLOR_BLUE( nSalColor
);
1461 COLORREF nBrushColor
= PALETTERGB( nRed
, nGreen
, nBlue
);
1462 HBRUSH hNewBrush
= nullptr;
1463 bool bStockBrush
= FALSE
;
1465 // search for stock brush (only screen, because printer have problems,
1466 // when we use stock objects)
1467 if ( !mrParent
.isPrinter() )
1469 for ( sal_uInt16 i
= 0; i
< pSalData
->mnStockBrushCount
; i
++ )
1471 if ( nBrushColor
== pSalData
->maStockBrushColorAry
[ i
] )
1473 hNewBrush
= pSalData
->mhStockBrushAry
[i
];
1483 if ( mrParent
.isPrinter() || !pSalData
->mhDitherDIB
)
1484 hNewBrush
= CreateSolidBrush( nBrushColor
);
1487 if ( 24 == reinterpret_cast<BITMAPINFOHEADER
*>(pSalData
->mpDitherDIB
)->biBitCount
)
1489 BYTE
* pTmp
= pSalData
->mpDitherDIBData
;
1490 long* pDitherDiff
= pSalData
->mpDitherDiff
;
1491 BYTE
* pDitherLow
= pSalData
->mpDitherLow
;
1492 BYTE
* pDitherHigh
= pSalData
->mpDitherHigh
;
1494 for( long nY
= 0L; nY
< 8L; nY
++ )
1496 for( long nX
= 0L; nX
< 8L; nX
++ )
1498 const long nThres
= aOrdDither16Bit
[ nY
][ nX
];
1499 *pTmp
++ = DMAP( nBlue
, nThres
);
1500 *pTmp
++ = DMAP( nGreen
, nThres
);
1501 *pTmp
++ = DMAP( nRed
, nThres
);
1505 hNewBrush
= CreateDIBPatternBrush( pSalData
->mhDitherDIB
, DIB_RGB_COLORS
);
1507 else if ( ImplIsSysColorEntry( nSalColor
) )
1509 nBrushColor
= PALRGB_TO_RGB( nBrushColor
);
1510 hNewBrush
= CreateSolidBrush( nBrushColor
);
1512 else if ( ImplIsPaletteEntry( nRed
, nGreen
, nBlue
) )
1513 hNewBrush
= CreateSolidBrush( nBrushColor
);
1516 BYTE
* pTmp
= pSalData
->mpDitherDIBData
;
1517 long* pDitherDiff
= pSalData
->mpDitherDiff
;
1518 BYTE
* pDitherLow
= pSalData
->mpDitherLow
;
1519 BYTE
* pDitherHigh
= pSalData
->mpDitherHigh
;
1521 for ( long nY
= 0L; nY
< 8L; nY
++ )
1523 for ( long nX
= 0L; nX
< 8L; nX
++ )
1525 const long nThres
= aOrdDither8Bit
[ nY
][ nX
];
1526 *pTmp
= DMAP( nRed
, nThres
) + DMAP( nGreen
, nThres
) * 6 + DMAP( nBlue
, nThres
) * 36;
1531 hNewBrush
= CreateDIBPatternBrush( pSalData
->mhDitherDIB
, DIB_PAL_COLORS
);
1535 bStockBrush
= FALSE
;
1539 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hNewBrush
);
1541 // destroy or save old brush
1544 if ( !mbStockBrush
)
1545 DeleteBrush( mhBrush
);
1548 mrParent
.mhDefBrush
= hOldBrush
;
1551 mnBrushColor
= nBrushColor
;
1552 mhBrush
= hNewBrush
;
1554 mbStockBrush
= bStockBrush
;
1557 void WinSalGraphicsImpl::SetXORMode( bool bSet
)
1560 ::SetROP2( mrParent
.getHDC(), bSet
? R2_XORPEN
: R2_COPYPEN
);
1563 void WinSalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor
)
1565 SetLineColor( ImplGetROPSalColor( nROPColor
) );
1568 void WinSalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor
)
1570 SetFillColor( ImplGetROPSalColor( nROPColor
) );
1573 void WinSalGraphicsImpl::drawPixel( long nX
, long nY
)
1577 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1578 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1579 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)1, (int)1, PATINVERT
);
1580 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1581 DeleteBrush( hBrush
);
1584 SetPixel( mrParent
.getHDC(), (int)nX
, (int)nY
, mnPenColor
);
1587 void WinSalGraphicsImpl::drawPixel( long nX
, long nY
, SalColor nSalColor
)
1589 COLORREF nCol
= PALETTERGB( SALCOLOR_RED( nSalColor
),
1590 SALCOLOR_GREEN( nSalColor
),
1591 SALCOLOR_BLUE( nSalColor
) );
1593 if ( !mrParent
.isPrinter() &&
1594 GetSalData()->mhDitherPal
&&
1595 ImplIsSysColorEntry( nSalColor
) )
1596 nCol
= PALRGB_TO_RGB( nCol
);
1600 HBRUSH hBrush
= CreateSolidBrush( nCol
);
1601 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1602 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)1, (int)1, PATINVERT
);
1603 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1604 DeleteBrush( hBrush
);
1607 ::SetPixel( mrParent
.getHDC(), (int)nX
, (int)nY
, nCol
);
1610 void WinSalGraphicsImpl::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
1612 MoveToEx( mrParent
.getHDC(), (int)nX1
, (int)nY1
, nullptr );
1614 // we must paint the endpoint
1615 int bPaintEnd
= TRUE
;
1633 LineTo( mrParent
.getHDC(), (int)nX2
, (int)nY2
);
1635 if ( bPaintEnd
&& !mrParent
.isPrinter() )
1639 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1640 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1641 PatBlt( mrParent
.getHDC(), (int)nX2
, (int)nY2
, (int)1, (int)1, PATINVERT
);
1642 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1643 DeleteBrush( hBrush
);
1646 SetPixel( mrParent
.getHDC(), (int)nX2
, (int)nY2
, mnPenColor
);
1650 void WinSalGraphicsImpl::drawRect( long nX
, long nY
, long nWidth
, long nHeight
)
1654 if ( !mrParent
.isPrinter() )
1656 PatBlt( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)nWidth
, (int)nHeight
,
1657 mbXORMode
? PATINVERT
: PATCOPY
);
1664 aWinRect
.right
= nX
+nWidth
;
1665 aWinRect
.bottom
= nY
+nHeight
;
1666 ::FillRect( mrParent
.getHDC(), &aWinRect
, mhBrush
);
1670 WIN_Rectangle( mrParent
.getHDC(), (int)nX
, (int)nY
, (int)(nX
+nWidth
), (int)(nY
+nHeight
) );
1673 void WinSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints
, SalPoint
* pPtAry
)
1675 // for NT, we can handover the array directly
1676 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1678 POINT
* pWinPtAry
= reinterpret_cast<POINT
*>(pPtAry
);
1680 // we assume there are at least 2 points (Polyline requires at least 2 point, see MSDN)
1681 // we must paint the endpoint for last line
1682 BOOL bPaintEnd
= TRUE
;
1683 if ( pWinPtAry
[nPoints
-2].x
== pWinPtAry
[nPoints
-1].x
)
1686 if ( pWinPtAry
[nPoints
-2].y
<= pWinPtAry
[nPoints
-1].y
)
1687 pWinPtAry
[nPoints
-1].y
++;
1689 pWinPtAry
[nPoints
-1].y
--;
1691 if ( pWinPtAry
[nPoints
-2].y
== pWinPtAry
[nPoints
-1].y
)
1694 if ( pWinPtAry
[nPoints
-2].x
<= pWinPtAry
[nPoints
-1].x
)
1695 pWinPtAry
[nPoints
-1].x
++;
1697 pWinPtAry
[nPoints
-1].x
--;
1700 // for Windows 95 and its maximum number of points
1701 if ( !Polyline( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1702 Polyline( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1704 if ( bPaintEnd
&& !mrParent
.isPrinter() )
1708 HBRUSH hBrush
= CreateSolidBrush( mnPenColor
);
1709 HBRUSH hOldBrush
= SelectBrush( mrParent
.getHDC(), hBrush
);
1710 PatBlt( mrParent
.getHDC(), (int)(pWinPtAry
[nPoints
-1].x
), (int)(pWinPtAry
[nPoints
-1].y
), (int)1, (int)1, PATINVERT
);
1711 SelectBrush( mrParent
.getHDC(), hOldBrush
);
1712 DeleteBrush( hBrush
);
1715 SetPixel( mrParent
.getHDC(), (int)(pWinPtAry
[nPoints
-1].x
), (int)(pWinPtAry
[nPoints
-1].y
), mnPenColor
);
1719 void WinSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
1721 // for NT, we can handover the array directly
1722 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1724 POINT
const * pWinPtAry
= reinterpret_cast<POINT
const *>(pPtAry
);
1725 // for Windows 95 and its maximum number of points
1726 if ( !Polygon( mrParent
.getHDC(), pWinPtAry
, (int)nPoints
) && (nPoints
> MAX_64KSALPOINTS
) )
1727 Polygon( mrParent
.getHDC(), pWinPtAry
, MAX_64KSALPOINTS
);
1730 void WinSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
1731 PCONSTSALPOINT
* pPtAry
)
1733 UINT aWinPointAry
[SAL_POLYPOLYCOUNT_STACKBUF
];
1735 UINT nPolyPolyPoints
= 0;
1739 if ( nPoly
<= SAL_POLYPOLYCOUNT_STACKBUF
)
1740 pWinPointAry
= aWinPointAry
;
1742 pWinPointAry
= new UINT
[nPoly
];
1744 for ( i
= 0; i
< (UINT
)nPoly
; i
++ )
1746 nPoints
= (UINT
)pPoints
[i
]+1;
1747 pWinPointAry
[i
] = nPoints
;
1748 nPolyPolyPoints
+= nPoints
;
1751 POINT aWinPointAryAry
[SAL_POLYPOLYPOINTS_STACKBUF
];
1752 POINT
* pWinPointAryAry
;
1753 if ( nPolyPolyPoints
<= SAL_POLYPOLYPOINTS_STACKBUF
)
1754 pWinPointAryAry
= aWinPointAryAry
;
1756 pWinPointAryAry
= new POINT
[nPolyPolyPoints
];
1757 // for NT, we can handover the array directly
1758 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1760 for ( i
= 0; i
< (UINT
)nPoly
; i
++ )
1762 nPoints
= pWinPointAry
[i
];
1763 const SalPoint
* pPolyAry
= pPtAry
[i
];
1764 memcpy( pWinPointAryAry
+n
, pPolyAry
, (nPoints
-1)*sizeof(POINT
) );
1765 pWinPointAryAry
[n
+nPoints
-1] = pWinPointAryAry
[n
];
1769 if ( !PolyPolygon( mrParent
.getHDC(), pWinPointAryAry
, reinterpret_cast<int*>(pWinPointAry
), (UINT
)nPoly
) &&
1770 (nPolyPolyPoints
> MAX_64KSALPOINTS
) )
1772 nPolyPolyPoints
= 0;
1776 nPolyPolyPoints
+= pWinPointAry
[(UINT
)nPoly
];
1779 while ( nPolyPolyPoints
< MAX_64KSALPOINTS
);
1781 if ( pWinPointAry
[(UINT
)nPoly
] > MAX_64KSALPOINTS
)
1782 pWinPointAry
[(UINT
)nPoly
] = MAX_64KSALPOINTS
;
1784 Polygon( mrParent
.getHDC(), pWinPointAryAry
, *pWinPointAry
);
1786 PolyPolygon( mrParent
.getHDC(), pWinPointAryAry
, reinterpret_cast<int*>(pWinPointAry
), nPoly
);
1789 if ( pWinPointAry
!= aWinPointAry
)
1790 delete [] pWinPointAry
;
1791 if ( pWinPointAryAry
!= aWinPointAryAry
)
1792 delete [] pWinPointAryAry
;
1795 bool WinSalGraphicsImpl::drawPolyLineBezier( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, const PolyFlags
* pFlgAry
)
1797 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1799 ImplRenderPath( mrParent
.getHDC(), nPoints
, pPtAry
, pFlgAry
);
1804 bool WinSalGraphicsImpl::drawPolygonBezier( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, const PolyFlags
* pFlgAry
)
1806 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1808 POINT aStackAry1
[SAL_POLY_STACKBUF
];
1809 BYTE aStackAry2
[SAL_POLY_STACKBUF
];
1810 POINT
* pWinPointAry
;
1812 if( nPoints
> SAL_POLY_STACKBUF
)
1814 pWinPointAry
= new POINT
[ nPoints
];
1815 pWinFlagAry
= new BYTE
[ nPoints
];
1819 pWinPointAry
= aStackAry1
;
1820 pWinFlagAry
= aStackAry2
;
1823 sal_uInt32
nPoints_i32(nPoints
);
1824 ImplPreparePolyDraw(true, 1, &nPoints_i32
, &pPtAry
, &pFlgAry
, pWinPointAry
, pWinFlagAry
);
1828 if( BeginPath( mrParent
.getHDC() ) )
1830 PolyDraw(mrParent
.getHDC(), pWinPointAry
, pWinFlagAry
, nPoints
);
1832 if( EndPath( mrParent
.getHDC() ) )
1834 if( StrokeAndFillPath( mrParent
.getHDC() ) )
1839 if( pWinPointAry
!= aStackAry1
)
1841 delete [] pWinPointAry
;
1842 delete [] pWinFlagAry
;
1848 bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
1849 const SalPoint
* const* pPtAry
, const PolyFlags
* const* pFlgAry
)
1851 static_assert( sizeof( POINT
) == sizeof( SalPoint
), "must be the same size" );
1853 sal_uLong nCurrPoly
, nTotalPoints
;
1854 const sal_uInt32
* pCurrPoints
= pPoints
;
1855 for( nCurrPoly
=0, nTotalPoints
=0; nCurrPoly
<nPoly
; ++nCurrPoly
)
1856 nTotalPoints
+= *pCurrPoints
++;
1858 POINT aStackAry1
[SAL_POLY_STACKBUF
];
1859 BYTE aStackAry2
[SAL_POLY_STACKBUF
];
1860 POINT
* pWinPointAry
;
1862 if( nTotalPoints
> SAL_POLY_STACKBUF
)
1864 pWinPointAry
= new POINT
[ nTotalPoints
];
1865 pWinFlagAry
= new BYTE
[ nTotalPoints
];
1869 pWinPointAry
= aStackAry1
;
1870 pWinFlagAry
= aStackAry2
;
1873 ImplPreparePolyDraw(true, nPoly
, pPoints
, pPtAry
, pFlgAry
, pWinPointAry
, pWinFlagAry
);
1877 if( BeginPath( mrParent
.getHDC() ) )
1879 PolyDraw(mrParent
.getHDC(), pWinPointAry
, pWinFlagAry
, nTotalPoints
);
1881 if( EndPath( mrParent
.getHDC() ) )
1883 if( StrokeAndFillPath( mrParent
.getHDC() ) )
1888 if( pWinPointAry
!= aStackAry1
)
1890 delete [] pWinPointAry
;
1891 delete [] pWinFlagAry
;
1897 void impAddB2DPolygonToGDIPlusGraphicsPathReal(
1898 Gdiplus::GraphicsPath
& rGraphicsPath
,
1899 const basegfx::B2DPolygon
& rPolygon
,
1902 sal_uInt32
nCount(rPolygon
.count());
1906 const sal_uInt32
nEdgeCount(rPolygon
.isClosed() ? nCount
: nCount
- 1);
1907 const bool bControls(rPolygon
.areControlPointsUsed());
1908 basegfx::B2DPoint
aCurr(rPolygon
.getB2DPoint(0));
1912 for(sal_uInt32
a(0); a
< nEdgeCount
; a
++)
1914 const sal_uInt32
nNextIndex((a
+ 1) % nCount
);
1915 const basegfx::B2DPoint
aNext(rPolygon
.getB2DPoint(nNextIndex
));
1916 const bool b1stControlPointUsed(bControls
&& rPolygon
.isNextControlPointUsed(a
));
1917 const bool b2ndControlPointUsed(bControls
&& rPolygon
.isPrevControlPointUsed(nNextIndex
));
1919 if(b1stControlPointUsed
|| b2ndControlPointUsed
)
1921 basegfx::B2DPoint
aCa(rPolygon
.getNextControlPoint(a
));
1922 basegfx::B2DPoint
aCb(rPolygon
.getPrevControlPoint(nNextIndex
));
1924 // tdf#99165 MS Gdiplus cannot handle creating correct extra geometry for fat lines
1925 // with LineCap or LineJoin when a bezier segment starts or ends trivial, e.g. has
1926 // no 1st or 2nd control point, despite that these are mathematicaly correct definitions
1927 // (basegfx can handle that).
1928 // Caution: This error (and it's correction) might be necessary for other graphical
1929 // sub-systems in a similar way.
1930 // tdf#101026 The 1st attempt to create a mathematically correct replacement control
1931 // vector was wrong. Best alternative is one as close as possible which means short.
1932 if(!b1stControlPointUsed
)
1934 aCa
= aCurr
+ ((aCb
- aCurr
) * 0.0005);
1936 else if(!b2ndControlPointUsed
)
1938 aCb
= aNext
+ ((aCa
- aNext
) * 0.0005);
1941 rGraphicsPath
.AddBezier(
1942 static_cast< Gdiplus::REAL
>(aCurr
.getX()), static_cast< Gdiplus::REAL
>(aCurr
.getY()),
1943 static_cast< Gdiplus::REAL
>(aCa
.getX()), static_cast< Gdiplus::REAL
>(aCa
.getY()),
1944 static_cast< Gdiplus::REAL
>(aCb
.getX()), static_cast< Gdiplus::REAL
>(aCb
.getY()),
1945 static_cast< Gdiplus::REAL
>(aNext
.getX()), static_cast< Gdiplus::REAL
>(aNext
.getY()));
1949 rGraphicsPath
.AddLine(
1950 static_cast< Gdiplus::REAL
>(aCurr
.getX()), static_cast< Gdiplus::REAL
>(aCurr
.getY()),
1951 static_cast< Gdiplus::REAL
>(aNext
.getX()), static_cast< Gdiplus::REAL
>(aNext
.getY()));
1954 if(a
+ 1 < nEdgeCount
)
1960 rGraphicsPath
.StartFigure();
1968 bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon
& rPolyPolygon
, double fTransparency
)
1970 const sal_uInt32
nCount(rPolyPolygon
.count());
1972 if(mbBrush
&& nCount
&& (fTransparency
>= 0.0 && fTransparency
< 1.0))
1974 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
1975 const sal_uInt8
aTrans((sal_uInt8
)255 - (sal_uInt8
)basegfx::fround(fTransparency
* 255.0));
1976 const Gdiplus::Color
aTestColor(aTrans
, SALCOLOR_RED(maFillColor
), SALCOLOR_GREEN(maFillColor
), SALCOLOR_BLUE(maFillColor
));
1977 const Gdiplus::SolidBrush
aSolidBrush(aTestColor
.GetValue());
1978 Gdiplus::GraphicsPath
aGraphicsPath(Gdiplus::FillModeAlternate
);
1980 for(sal_uInt32
a(0); a
< nCount
; a
++)
1984 // #i101491# not needed for first run
1985 aGraphicsPath
.StartFigure();
1988 impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath
, rPolyPolygon
.getB2DPolygon(a
), false);
1990 aGraphicsPath
.CloseFigure();
1993 if(mrParent
.getAntiAliasB2DDraw())
1995 aGraphics
.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias
);
1999 aGraphics
.SetSmoothingMode(Gdiplus::SmoothingModeNone
);
2002 if(mrParent
.isPrinter())
2005 // Normally GdiPlus should not be used for printing at all since printers cannot
2006 // print transparent filled polygon geometry and normally this does not happen
2007 // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation
2008 // and no transparent parts should remain for printing. But this can be overridden
2009 // by the user and thus happens. This call can only come (currently) from
2010 // OutputDevice::DrawTransparent, see comments there with the same TaskID.
2011 // If it is used, the mapping for the printer is wrong and needs to be corrected. I
2012 // checked that there is *no* transformation set and estimated that a stable factor
2013 // dependent of the printer's DPI is used. Create and set a transformation here to
2015 const Gdiplus::REAL
aDpiX(aGraphics
.GetDpiX());
2016 const Gdiplus::REAL
aDpiY(aGraphics
.GetDpiY());
2018 aGraphics
.ResetTransform();
2019 aGraphics
.ScaleTransform(Gdiplus::REAL(100.0) / aDpiX
, Gdiplus::REAL(100.0) / aDpiY
, Gdiplus::MatrixOrderAppend
);
2022 aGraphics
.FillPath(&aSolidBrush
, &aGraphicsPath
);
2028 bool WinSalGraphicsImpl::drawPolyLine(
2029 const basegfx::B2DPolygon
& rPolygon
,
2030 double fTransparency
,
2031 const basegfx::B2DVector
& rLineWidths
,
2032 basegfx::B2DLineJoin eLineJoin
,
2033 css::drawing::LineCap eLineCap
,
2034 double fMiterMinimumAngle
)
2036 const sal_uInt32
nCount(rPolygon
.count());
2040 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2041 const sal_uInt8 aTrans
= (sal_uInt8
)basegfx::fround( 255 * (1.0 - fTransparency
) );
2042 const Gdiplus::Color
aTestColor(aTrans
, SALCOLOR_RED(maLineColor
), SALCOLOR_GREEN(maLineColor
), SALCOLOR_BLUE(maLineColor
));
2043 Gdiplus::Pen
aPen(aTestColor
.GetValue(), Gdiplus::REAL(rLineWidths
.getX()));
2044 Gdiplus::GraphicsPath
aGraphicsPath(Gdiplus::FillModeAlternate
);
2045 bool bNoLineJoin(false);
2049 case basegfx::B2DLineJoin::NONE
:
2051 if(basegfx::fTools::more(rLineWidths
.getX(), 0.0))
2057 case basegfx::B2DLineJoin::Bevel
:
2059 aPen
.SetLineJoin(Gdiplus::LineJoinBevel
);
2062 case basegfx::B2DLineJoin::Miter
:
2064 const Gdiplus::REAL
aMiterLimit(1.0/sin(fMiterMinimumAngle
/2.0));
2066 aPen
.SetMiterLimit(aMiterLimit
);
2067 // tdf#99165 MS's LineJoinMiter creates non standard conform miter additional
2068 // graphics, somewhere clipped in some distance from the edge point, dependent
2069 // of MiterLimit. The more default-like option is LineJoinMiterClipped, so use
2071 aPen
.SetLineJoin(Gdiplus::LineJoinMiterClipped
);
2074 case basegfx::B2DLineJoin::Round
:
2076 aPen
.SetLineJoin(Gdiplus::LineJoinRound
);
2083 default: /*css::drawing::LineCap_BUTT*/
2088 case css::drawing::LineCap_ROUND
:
2090 aPen
.SetStartCap(Gdiplus::LineCapRound
);
2091 aPen
.SetEndCap(Gdiplus::LineCapRound
);
2094 case css::drawing::LineCap_SQUARE
:
2096 aPen
.SetStartCap(Gdiplus::LineCapSquare
);
2097 aPen
.SetEndCap(Gdiplus::LineCapSquare
);
2102 impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath
, rPolygon
, bNoLineJoin
);
2104 if(rPolygon
.isClosed() && !bNoLineJoin
)
2106 // #i101491# needed to create the correct line joins
2107 aGraphicsPath
.CloseFigure();
2110 if(mrParent
.getAntiAliasB2DDraw())
2112 aGraphics
.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias
);
2116 aGraphics
.SetSmoothingMode(Gdiplus::SmoothingModeNone
);
2119 aGraphics
.DrawPath(&aPen
, &aGraphicsPath
);
2125 void paintToGdiPlus(
2126 Gdiplus::Graphics
& rGraphics
,
2127 const SalTwoRect
& rTR
,
2128 Gdiplus::Bitmap
& rBitmap
)
2130 // only parts of source are used
2131 Gdiplus::PointF aDestPoints
[3];
2132 Gdiplus::ImageAttributes aAttributes
;
2134 // define target region as paralellogram
2135 aDestPoints
[0].X
= Gdiplus::REAL(rTR
.mnDestX
);
2136 aDestPoints
[0].Y
= Gdiplus::REAL(rTR
.mnDestY
);
2137 aDestPoints
[1].X
= Gdiplus::REAL(rTR
.mnDestX
+ rTR
.mnDestWidth
);
2138 aDestPoints
[1].Y
= Gdiplus::REAL(rTR
.mnDestY
);
2139 aDestPoints
[2].X
= Gdiplus::REAL(rTR
.mnDestX
);
2140 aDestPoints
[2].Y
= Gdiplus::REAL(rTR
.mnDestY
+ rTR
.mnDestHeight
);
2142 aAttributes
.SetWrapMode(Gdiplus::WrapModeTileFlipXY
);
2144 rGraphics
.DrawImage(
2148 Gdiplus::REAL(rTR
.mnSrcX
),
2149 Gdiplus::REAL(rTR
.mnSrcY
),
2150 Gdiplus::REAL(rTR
.mnSrcWidth
),
2151 Gdiplus::REAL(rTR
.mnSrcHeight
),
2156 void setInterpolationMode(
2157 Gdiplus::Graphics
& rGraphics
,
2163 const bool bSameWidth(rSrcWidth
== rDestWidth
);
2164 const bool bSameHeight(rSrcHeight
== rDestHeight
);
2166 if(bSameWidth
&& bSameHeight
)
2169 //Gdiplus::InterpolationModeInvalid is missing on mingw
2170 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2172 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeInvalid
);
2175 else if(rDestWidth
> rSrcWidth
&& rDestHeight
> rSrcHeight
)
2177 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2179 else if(rDestWidth
< rSrcWidth
&& rDestHeight
< rSrcHeight
)
2181 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeBicubic
);
2185 rGraphics
.SetInterpolationMode(Gdiplus::InterpolationModeDefault
);
2189 bool WinSalGraphicsImpl::tryDrawBitmapGdiPlus(const SalTwoRect
& rTR
, const SalBitmap
& rSrcBitmap
)
2191 if(rTR
.mnSrcWidth
&& rTR
.mnSrcHeight
&& rTR
.mnDestWidth
&& rTR
.mnDestHeight
)
2193 assert(dynamic_cast<const WinSalBitmap
*>(&rSrcBitmap
));
2195 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSrcBitmap
);
2196 std::shared_ptr
< Gdiplus::Bitmap
> aARGB(rSalBitmap
.ImplGetGdiPlusBitmap());
2200 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2202 setInterpolationMode(
2221 bool WinSalGraphicsImpl::blendBitmap(
2228 bool WinSalGraphicsImpl::blendAlphaBitmap(
2237 bool WinSalGraphicsImpl::drawAlphaBitmap(
2238 const SalTwoRect
& rTR
,
2239 const SalBitmap
& rSrcBitmap
,
2240 const SalBitmap
& rAlphaBmp
)
2242 if(rTR
.mnSrcWidth
&& rTR
.mnSrcHeight
&& rTR
.mnDestWidth
&& rTR
.mnDestHeight
)
2244 assert(dynamic_cast<const WinSalBitmap
*>(&rSrcBitmap
));
2245 assert(dynamic_cast<const WinSalBitmap
*>(&rAlphaBmp
));
2247 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSrcBitmap
);
2248 const WinSalBitmap
& rSalAlpha
= static_cast< const WinSalBitmap
& >(rAlphaBmp
);
2249 std::shared_ptr
< Gdiplus::Bitmap
> aARGB(rSalBitmap
.ImplGetGdiPlusBitmap(&rSalAlpha
));
2253 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2255 setInterpolationMode(
2274 bool WinSalGraphicsImpl::drawTransformedBitmap(
2275 const basegfx::B2DPoint
& rNull
,
2276 const basegfx::B2DPoint
& rX
,
2277 const basegfx::B2DPoint
& rY
,
2278 const SalBitmap
& rSourceBitmap
,
2279 const SalBitmap
* pAlphaBitmap
)
2281 assert(dynamic_cast<const WinSalBitmap
*>(&rSourceBitmap
));
2282 assert(!pAlphaBitmap
|| dynamic_cast<const WinSalBitmap
*>(pAlphaBitmap
));
2284 const WinSalBitmap
& rSalBitmap
= static_cast< const WinSalBitmap
& >(rSourceBitmap
);
2285 const WinSalBitmap
* pSalAlpha
= static_cast< const WinSalBitmap
* >(pAlphaBitmap
);
2286 std::shared_ptr
< Gdiplus::Bitmap
> aARGB(rSalBitmap
.ImplGetGdiPlusBitmap(pSalAlpha
));
2290 const long nSrcWidth(aARGB
->GetWidth());
2291 const long nSrcHeight(aARGB
->GetHeight());
2293 if(nSrcWidth
&& nSrcHeight
)
2295 const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX
- rNull
).getLength()));
2296 const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY
- rNull
).getLength()));
2298 if(nDestWidth
&& nDestHeight
)
2300 Gdiplus::Graphics
aGraphics(mrParent
.getHDC());
2301 Gdiplus::PointF aDestPoints
[3];
2302 Gdiplus::ImageAttributes aAttributes
;
2304 setInterpolationMode(
2311 // this mode is only capable of drawing the whole bitmap to a paralellogram
2312 aDestPoints
[0].X
= Gdiplus::REAL(rNull
.getX());
2313 aDestPoints
[0].Y
= Gdiplus::REAL(rNull
.getY());
2314 aDestPoints
[1].X
= Gdiplus::REAL(rX
.getX());
2315 aDestPoints
[1].Y
= Gdiplus::REAL(rX
.getY());
2316 aDestPoints
[2].X
= Gdiplus::REAL(rY
.getX());
2317 aDestPoints
[2].Y
= Gdiplus::REAL(rY
.getY());
2319 aAttributes
.SetWrapMode(Gdiplus::WrapModeTileFlipXY
);
2321 aGraphics
.DrawImage(
2327 Gdiplus::REAL(nSrcWidth
),
2328 Gdiplus::REAL(nSrcHeight
),
2340 bool WinSalGraphicsImpl::drawGradient(const tools::PolyPolygon
& /*rPolygon*/,
2341 const Gradient
& /*rGradient*/)
2346 bool WinSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey
& /*rControlCacheKey*/, int /*nX*/, int /*nY*/)
2351 bool WinSalGraphicsImpl::RenderAndCacheNativeControl(OpenGLCompatibleDC
& /*rWhite*/, OpenGLCompatibleDC
& /*rBlack*/,
2352 int /*nX*/, int /*nY*/ , ControlCacheKey
& /*aControlCacheKey*/)
2357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */