Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / gdi / gdiimpl.cxx
blobe4823a2c64528cc93a5654656e5928892230f292
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <svsys.h>
22 #include "gdiimpl.hxx"
24 #include <stdio.h>
25 #include <string.h>
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"
43 #if defined _MSC_VER
44 #ifndef min
45 #define min(a,b) (((a) < (b)) ? (a) : (b))
46 #endif
47 #ifndef max
48 #define max(a,b) (((a) > (b)) ? (a) : (b))
49 #endif
50 #endif
52 #if defined _MSC_VER
53 #pragma warning(push, 1)
54 #endif
56 #ifdef __MINGW32__
57 #ifdef GetObject
58 #undef GetObject
59 #endif
60 #endif
62 #include <gdiplus.h>
63 #include <gdiplusenums.h>
64 #include <gdipluscolor.h>
66 #if defined _MSC_VER
67 #pragma warning(pop)
68 #endif
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
85 namespace {
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 )
90 if( nPoints )
92 sal_uInt16 i;
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 );
98 ++pPtAry; ++pFlgAry;
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,
119 sal_uLong nPoly,
120 const sal_uInt32* pPoints,
121 const SalPoint* const* pPtAry,
122 const BYTE* const* pFlgAry,
123 POINT* pWinPointAry,
124 BYTE* pWinFlagAry )
126 sal_uLong nCurrPoly;
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;
135 if( nCurrPoints )
137 // start figure
138 *pWinPointAry++ = *pCurrPoint++;
139 *pWinFlagAry++ = PT_MOVETO;
140 ++pCurrFlag;
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 ) )
154 // control point one
155 *pWinPointAry++ = *pCurrPoint++;
156 *pWinFlagAry++ = PT_BEZIERTO;
158 // control point two
159 *pWinPointAry++ = *pCurrPoint++;
160 *pWinFlagAry++ = PT_BEZIERTO;
162 // end point
163 *pWinPointAry++ = *pCurrPoint++;
164 *pWinFlagAry++ = PT_BEZIERTO;
166 nCurrPoint += 3;
167 pCurrFlag += 3;
168 continue;
172 // regular line point
173 *pWinPointAry++ = *pCurrPoint++;
174 *pWinFlagAry++ = PT_LINETO;
175 ++pCurrFlag;
176 ++nCurrPoint;
179 // end figure?
180 if( bCloseFigures )
181 pWinFlagAry[-1] |= PT_CLOSEFIGURE;
187 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
189 { 0, 0, 0, 0 },
190 { 0, 0, 0x80, 0 },
191 { 0, 0x80, 0, 0 },
192 { 0, 0x80, 0x80, 0 },
193 { 0x80, 0, 0, 0 },
194 { 0x80, 0, 0x80, 0 },
195 { 0x80, 0x80, 0, 0 },
196 { 0x80, 0x80, 0x80, 0 },
197 { 0xC0, 0xC0, 0xC0, 0 },
198 { 0, 0, 0xFF, 0 },
199 { 0, 0xFF, 0, 0 },
200 { 0, 0xFF, 0xFF, 0 },
201 { 0xFF, 0, 0, 0 },
202 { 0xFF, 0, 0xFF, 0 },
203 { 0xFF, 0xFF, 0, 0 },
204 { 0xFF, 0xFF, 0xFF, 0 }
207 static PALETTEENTRY aImplExtraColor1 =
209 0, 184, 255, 0
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 )
238 SalColor nSalColor;
239 if ( nROPColor == SAL_ROP_0 )
240 nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
241 else
242 nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
243 return nSalColor;
246 int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
248 // dither color?
249 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
250 return TRUE;
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 )
258 return TRUE;
261 // extra color?
262 if ( aImplExtraColor1.peRed == nRed &&
263 aImplExtraColor1.peGreen == nGreen &&
264 aImplExtraColor1.peBlue == nBlue )
266 return TRUE;
269 return FALSE;
274 WinSalGraphicsImpl::WinSalGraphicsImpl(WinSalGraphics& rParent):
275 mrParent(rParent),
276 mbXORMode(false),
277 mhPen(0),
278 mhBrush(0)
282 WinSalGraphicsImpl::~WinSalGraphicsImpl()
284 if ( mhPen )
286 if ( !mbStockPen )
287 DeletePen( mhPen );
290 if ( mhBrush )
292 if ( !mbStockBrush )
293 DeleteBrush( mhBrush );
298 void WinSalGraphicsImpl::Init()
302 void WinSalGraphicsImpl::freeResources()
306 bool WinSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uLong)
308 return false;
311 void WinSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
313 HDC hSrcDC;
314 DWORD nRop;
316 if ( pSrcGraphics )
317 hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->getHDC();
318 else
319 hSrcDC = mrParent.getHDC();
321 if ( mbXORMode )
322 nRop = SRCINVERT;
323 else
324 nRop = SRCCOPY;
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,
332 hSrcDC,
333 (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
334 nRop );
336 else
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,
342 hSrcDC,
343 (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
344 (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight,
345 nRop );
346 SetStretchBltMode( mrParent.getHDC(), nOldStretchMode );
350 void ImplCalcOutSideRgn( const RECT& rSrcRect,
351 int nLeft, int nTop, int nRight, int nBottom,
352 HRGN& rhInvalidateRgn )
354 HRGN hTempRgn;
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,
394 sal_uInt16 nFlags )
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
407 RECT aSrcRect;
408 RECT aClipRect;
409 RECT aTempRect;
410 RECT aTempRect2;
411 HRGN hTempRgn;
412 HWND hWnd;
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
423 POINT aPt;
424 aPt.x = 0;
425 aPt.y = 0;
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;
431 hInvalidateRgn = 0;
433 // compute the parts that are off screen (ie invisible)
434 RECT theScreen;
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
439 HRGN hTempRgn2 = 0;
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 );
452 POINT aPt2;
453 aPt2.x = 0;
454 aPt2.y = 0;
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,
471 hInvalidateRgn );
474 // retrieve the top-most (z-order) child window
475 hWnd = GetWindow( GetDesktopWindow(), GW_CHILD );
476 while ( hWnd )
478 if ( hWnd == hWndTopWindow )
479 break;
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)
493 if ( !hTempRgn2 )
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 );
511 if ( hTempRgn2 )
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,
544 mrParent.getHDC(),
545 (int)nSrcX, (int)nSrcY,
546 SRCCOPY );
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) )
564 bInvalidate = false;
566 DeleteRegion( hTempRgn );
568 if ( bInvalidate )
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 );
585 namespace {
587 void ImplDrawBitmap( HDC hDC, const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap,
588 bool bPrinter, int nDrawMode )
590 if( hDC )
592 HGLOBAL hDrawDIB;
593 HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB();
594 WinSalBitmap* pTmpSalBmp = NULL;
595 bool bPrintDDB = ( bPrinter && hDrawDDB );
597 if( bPrintDDB )
599 pTmpSalBmp = new WinSalBitmap;
600 pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() );
601 hDrawDIB = pTmpSalBmp->ImplGethDIB();
603 else
604 hDrawDIB = rSalBitmap.ImplGethDIB();
606 if( hDrawDIB )
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 );
614 StretchDIBits( hDC,
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 );
631 if( bMono )
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)
642 SalColor nCol;
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) )
657 BitBlt( hDC,
658 (int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
659 (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
660 hBmpDC,
661 (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
662 nDrawMode );
664 else
666 const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
668 StretchBlt( hDC,
669 (int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
670 (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
671 hBmpDC,
672 (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
673 (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight,
674 nDrawMode );
676 SetStretchBltMode( hDC, nOldStretchMode );
679 if( bMono )
681 SetBkColor( hDC, nOldBkColor );
682 ::SetTextColor( hDC, nOldTextColor );
685 ImplReleaseCachedDC( CACHED_HDC_DRAW );
688 if( bPrintDDB )
689 delete pTmpSalBmp;
695 void WinSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
697 bool bTryDirectPaint(!mrParent.isPrinter() && !mbXORMode);
699 if(bTryDirectPaint)
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))
713 return;
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;
731 const Point aPoint;
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 );
749 else
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 );
764 delete pTmpSalBmp;
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 );
773 delete 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))
786 return;
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 )
817 WinSalBitmap aTmp;
819 if( aTmp.Create( rTransparentBitmap, &mrParent ) )
820 ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY );
822 else
823 ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY );
825 // now MemDC contains background, MaskDC the transparency mask
827 // #105055# Respect XOR mode
828 if( mbXORMode )
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
835 else
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
844 // copy to output DC
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
851 if( hMemBitmap )
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 = {
868 AC_SRC_OVER,
870 sal::static_int_cast<sal_uInt8>(255 - 255L*nTransparency/100),
874 // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
875 // that to dest hdc
876 bool bRet = AlphaBlend( mrParent.getHDC(), nX, nY, nWidth, nHeight,
877 hMemDC, 0,0,1,1,
878 aFunc ) == TRUE;
880 ImplReleaseCachedDC( CACHED_HDC_1 );
882 return bRet;
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 )
905 WinSalBitmap aTmp;
907 if( aTmp.Create( rSalBitmap, &mrParent ) )
908 ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL );
910 else
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;
923 nDX = labs( nDX );
924 nDY = labs( nDY );
926 HDC hDC = mrParent.getHDC();
927 HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
928 HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
929 bool bRet;
931 bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE;
932 ImplReleaseCachedDC( CACHED_HDC_1 );
934 if( bRet )
936 pSalBitmap = new WinSalBitmap;
938 if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
940 delete pSalBitmap;
941 pSalBitmap = NULL;
944 else
946 // #124826# avoid resource leak! Happens when running without desktop access (remote desktop, service, may be screensavers)
947 DeleteBitmap( hBmpBitmap );
950 return pSalBitmap;
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 );
959 else
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 );
997 else
999 RECT aRect;
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 )
1010 HPEN hPen;
1011 HPEN hOldPen;
1012 HBRUSH hBrush;
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 );
1019 else
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;
1034 else
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 );
1043 POINT* pWinPtAry;
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 );
1055 else
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 )
1065 DeletePen( hPen );
1066 else
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() );
1083 if( pFrame )
1085 if( pFrame->maGeometry.nWidth )
1086 return pFrame->maGeometry.nWidth;
1087 else
1089 // TODO: perhaps not needed, maGeometry should always be up-to-date
1090 RECT aRect;
1091 GetClientRect( mrParent.gethWnd(), &aRect );
1092 return aRect.right;
1097 return 0;
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;
1145 if(bUsePolygon)
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());
1156 if( nCount )
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),
1176 1));
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;
1189 POINT aPOINT;
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 );
1200 else
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;
1212 else
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());
1228 if(nW && nH)
1230 const long nRight(aRectIter->Left() + nW);
1231 const long nBottom(aRectIter->Top() + nH);
1233 if(bFirstClipRect)
1235 pBoundRect->left = aRectIter->Left();
1236 pBoundRect->top = aRectIter->Top();
1237 pBoundRect->right = nRight;
1238 pBoundRect->bottom = nBottom;
1239 bFirstClipRect = false;
1241 else
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;
1268 pNextClipRect++;
1270 else
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 );
1304 pRect++;
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
1325 //RECT aBound;
1326 //const int aRegionType = GetRgnBox(mrParent.mhRegion, &aBound);
1328 //bool bBla = true;
1330 else
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
1337 return true;
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
1347 if ( mhPen )
1349 if ( !mbStockPen )
1350 DeletePen( mhPen );
1352 else
1353 mrParent.mhDefPen = hOldPen;
1355 // set new data
1356 mhPen = hNewPen;
1357 mbPen = FALSE;
1358 mbStockPen = TRUE;
1361 void WinSalGraphicsImpl::SetLineColor( SalColor nSalColor )
1363 maLineColor = nSalColor;
1364 COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
1365 SALCOLOR_GREEN( nSalColor ),
1366 SALCOLOR_BLUE( nSalColor ) );
1367 HPEN hNewPen = 0;
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];
1380 bStockPen = TRUE;
1381 break;
1386 // create new pen
1387 if ( !hNewPen )
1389 if ( !mrParent.isPrinter() )
1391 if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
1392 nPenColor = PALRGB_TO_RGB( nPenColor );
1395 hNewPen = CreatePen( PS_SOLID, mrParent.mnPenWidth, nPenColor );
1396 bStockPen = FALSE;
1399 // select new pen
1400 HPEN hOldPen = SelectPen( mrParent.getHDC(), hNewPen );
1402 // destroy or save old pen
1403 if ( mhPen )
1405 if ( !mbStockPen )
1406 DeletePen( mhPen );
1408 else
1409 mrParent.mhDefPen = hOldPen;
1411 // set new data
1412 mnPenColor = nPenColor;
1413 mhPen = hNewPen;
1414 mbPen = TRUE;
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
1425 if ( mhBrush )
1427 if ( !mbStockBrush )
1428 DeleteBrush( mhBrush );
1430 else
1431 mrParent.mhDefBrush = hOldBrush;
1433 // set new data
1434 mhBrush = hNewBrush;
1435 mbBrush = FALSE;
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];
1459 bStockBrush = TRUE;
1460 break;
1465 // create new brush
1466 if ( !hNewBrush )
1468 if ( mrParent.isPrinter() || !pSalData->mhDitherDIB )
1469 hNewBrush = CreateSolidBrush( nBrushColor );
1470 else
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 );
1499 else
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;
1512 pTmp++;
1516 hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
1520 bStockBrush = FALSE;
1523 // select new brush
1524 HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hNewBrush );
1526 // destroy or save old brush
1527 if ( mhBrush )
1529 if ( !mbStockBrush )
1530 DeleteBrush( mhBrush );
1532 else
1533 mrParent.mhDefBrush = hOldBrush;
1535 // set new data
1536 mnBrushColor = nBrushColor;
1537 mhBrush = hNewBrush;
1538 mbBrush = TRUE;
1539 mbStockBrush = bStockBrush;
1542 void WinSalGraphicsImpl::SetXORMode( bool bSet, bool )
1544 mbXORMode = bSet;
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 )
1560 if ( mbXORMode )
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 );
1568 else
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 );
1583 if ( mbXORMode )
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 );
1591 else
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;
1601 if ( nX1 == nX2 )
1603 bPaintEnd = FALSE;
1604 if ( nY1 <= nY2 )
1605 nY2++;
1606 else
1607 nY2--;
1609 if ( nY1 == nY2 )
1611 bPaintEnd = FALSE;
1612 if ( nX1 <= nX2 )
1613 nX2++;
1614 else
1615 nX2--;
1618 LineTo( mrParent.getHDC(), (int)nX2, (int)nY2 );
1620 if ( bPaintEnd && !mrParent.isPrinter() )
1622 if ( mbXORMode )
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 );
1630 else
1631 SetPixel( mrParent.getHDC(), (int)nX2, (int)nY2, mnPenColor );
1635 void WinSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight )
1637 if ( !mbPen )
1639 if ( !mrParent.isPrinter() )
1641 PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight,
1642 mbXORMode ? PATINVERT : PATCOPY );
1644 else
1646 RECT aWinRect;
1647 aWinRect.left = nX;
1648 aWinRect.top = nY;
1649 aWinRect.right = nX+nWidth;
1650 aWinRect.bottom = nY+nHeight;
1651 ::FillRect( mrParent.getHDC(), &aWinRect, mhBrush );
1654 else
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 )
1671 bPaintEnd = FALSE;
1672 if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y )
1673 pWinPtAry[nPoints-1].y++;
1674 else
1675 pWinPtAry[nPoints-1].y--;
1677 if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y )
1679 bPaintEnd = FALSE;
1680 if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x )
1681 pWinPtAry[nPoints-1].x++;
1682 else
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() )
1692 if ( mbXORMode )
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 );
1700 else
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];
1721 UINT* pWinPointAry;
1722 UINT nPolyPolyPoints = 0;
1723 UINT nPoints;
1724 UINT i;
1726 if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
1727 pWinPointAry = aWinPointAry;
1728 else
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;
1742 else
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" );
1747 UINT n = 0;
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];
1754 n += nPoints;
1757 if ( !WIN_PolyPolygon( mrParent.getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
1758 (nPolyPolyPoints > MAX_64KSALPOINTS) )
1760 nPolyPolyPoints = 0;
1761 nPoly = 0;
1764 nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
1765 nPoly++;
1767 while ( nPolyPolyPoints < MAX_64KSALPOINTS );
1768 nPoly--;
1769 if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
1770 pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
1771 if ( nPoly == 1 )
1772 WIN_Polygon( mrParent.getHDC(), pWinPointAryAry, *pWinPointAry );
1773 else
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 );
1792 return true;
1793 #else
1794 return false;
1795 #endif
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;
1808 BYTE* pWinFlagAry;
1809 if( nPoints > SAL_POLY_STACKBUF )
1811 pWinPointAry = new POINT[ nPoints ];
1812 pWinFlagAry = new BYTE[ nPoints ];
1814 else
1816 pWinPointAry = aStackAry1;
1817 pWinFlagAry = aStackAry2;
1820 sal_uInt32 nPoints_i32(nPoints);
1821 ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
1823 bool bRet( false );
1825 if( BeginPath( mrParent.getHDC() ) )
1827 PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nPoints);
1829 if( EndPath( mrParent.getHDC() ) )
1831 if( StrokeAndFillPath( mrParent.getHDC() ) )
1832 bRet = true;
1836 if( pWinPointAry != aStackAry1 )
1838 delete [] pWinPointAry;
1839 delete [] pWinFlagAry;
1842 return bRet;
1843 #else
1844 return false;
1845 #endif
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;
1864 BYTE* pWinFlagAry;
1865 if( nTotalPoints > SAL_POLY_STACKBUF )
1867 pWinPointAry = new POINT[ nTotalPoints ];
1868 pWinFlagAry = new BYTE[ nTotalPoints ];
1870 else
1872 pWinPointAry = aStackAry1;
1873 pWinFlagAry = aStackAry2;
1876 ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
1878 bool bRet( false );
1880 if( BeginPath( mrParent.getHDC() ) )
1882 PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints);
1884 if( EndPath( mrParent.getHDC() ) )
1886 if( StrokeAndFillPath( mrParent.getHDC() ) )
1887 bRet = true;
1891 if( pWinPointAry != aStackAry1 )
1893 delete [] pWinPointAry;
1894 delete [] pWinFlagAry;
1897 return bRet;
1898 #else
1899 return false;
1900 #endif
1903 void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
1905 sal_uInt32 nCount(rPolygon.count());
1907 if(nCount)
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());
1929 else
1931 Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY());
1934 if(a + 1 < nEdgeCount)
1936 aCurr = aNext;
1938 if(bNoLineJoin)
1940 Gdiplus::DllExports::GdipStartPathFigure(pPath);
1947 void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
1949 sal_uInt32 nCount(rPolygon.count());
1951 if(nCount)
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(
1968 pPath,
1969 aCurr.getX(), aCurr.getY(),
1970 aCa.getX(), aCa.getY(),
1971 aCb.getX(), aCb.getY(),
1972 aNext.getX(), aNext.getY());
1974 else
1976 Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY());
1979 if(a + 1 < nEdgeCount)
1981 aCurr = aNext;
1983 if(bNoLineJoin)
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++)
2009 if(0 != 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);
2022 else
2024 Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone);
2027 if(mrParent.isPrinter())
2029 // #i121591#
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
2039 // correct this.
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);
2055 return true;
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());
2067 if(mbPen && nCount)
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);
2079 switch(eLineJoin)
2081 default : // basegfx::B2DLINEJOIN_NONE :
2083 if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
2085 bNoLineJoin = true;
2087 break;
2089 case basegfx::B2DLINEJOIN_BEVEL :
2091 Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinBevel);
2092 break;
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);
2100 break;
2102 case basegfx::B2DLINEJOIN_ROUND :
2104 Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinRound);
2105 break;
2109 switch(eLineCap)
2111 default: /*com::sun::star::drawing::LineCap_BUTT*/
2113 // nothing to do
2114 break;
2116 case com::sun::star::drawing::LineCap_ROUND:
2118 Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapRound);
2119 Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapRound);
2120 break;
2122 case com::sun::star::drawing::LineCap_SQUARE:
2124 Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapSquare);
2125 Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapSquare);
2126 break;
2130 if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
2132 impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath, rPolygon, bNoLineJoin);
2134 else
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);
2149 else
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);
2161 return true;
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(
2184 &rBitmap,
2185 aDestPoints,
2187 Gdiplus::REAL(rTR.mnSrcX),
2188 Gdiplus::REAL(rTR.mnSrcY),
2189 Gdiplus::REAL(rTR.mnSrcWidth),
2190 Gdiplus::REAL(rTR.mnSrcHeight),
2191 Gdiplus::UnitPixel,
2192 &aAttributes,
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)
2209 #ifdef __MINGW32__
2210 //Gdiplus::InterpolationModeInvalid is missing on mingw
2211 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault);
2212 #else
2213 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid);
2214 #endif
2216 else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight)
2218 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault);
2220 else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight)
2222 rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic);
2224 else
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());
2237 if(aARGB.get())
2239 Gdiplus::Graphics aGraphics(mrParent.getHDC());
2241 setInterpolationMode(
2242 aGraphics,
2243 rTR.mnSrcWidth,
2244 rTR.mnDestWidth,
2245 rTR.mnSrcHeight,
2246 rTR.mnDestHeight);
2248 paintToGdiPlus(
2249 aGraphics,
2250 rTR,
2251 *aARGB.get());
2253 return true;
2257 return false;
2260 bool WinSalGraphicsImpl::blendBitmap(
2261 const SalTwoRect&,
2262 const SalBitmap&)
2264 return false;
2267 bool WinSalGraphicsImpl::blendAlphaBitmap(
2268 const SalTwoRect&,
2269 const SalBitmap&,
2270 const SalBitmap&,
2271 const SalBitmap&)
2273 return false;
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));
2287 if(aARGB.get())
2289 Gdiplus::Graphics aGraphics(mrParent.getHDC());
2291 setInterpolationMode(
2292 aGraphics,
2293 rTR.mnSrcWidth,
2294 rTR.mnDestWidth,
2295 rTR.mnSrcHeight,
2296 rTR.mnDestHeight);
2298 paintToGdiPlus(
2299 aGraphics,
2300 rTR,
2301 *aARGB.get());
2303 return true;
2307 return false;
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));
2321 if(aARGB.get())
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(
2338 aGraphics,
2339 nSrcWidth,
2340 nDestWidth,
2341 nSrcHeight,
2342 nDestHeight);
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(
2355 aARGB.get(),
2356 aDestPoints,
2358 Gdiplus::REAL(0.0),
2359 Gdiplus::REAL(0.0),
2360 Gdiplus::REAL(nSrcWidth),
2361 Gdiplus::REAL(nSrcHeight),
2362 Gdiplus::UnitPixel,
2363 &aAttributes,
2369 return true;
2372 return false;
2375 bool WinSalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/,
2376 const Gradient& /*rGradient*/)
2378 return false;
2381 bool WinSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey& /*rControlCacheKey*/, int /*nX*/, int /*nY*/)
2383 return false;
2386 bool WinSalGraphicsImpl::RenderAndCacheNativeControl(OpenGLCompatibleDC& /*rWhite*/, OpenGLCompatibleDC& /*rBlack*/,
2387 int /*nX*/, int /*nY*/ , ControlCacheKey& /*aControlCacheKey*/)
2389 return false;
2392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */