merged tag ooo/DEV300_m102
[LibreOffice.git] / vcl / win / source / gdi / salgdi.cxx
blob73d93d42dd03dd76aa27b24cee574b49a29d190b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include <stdio.h>
32 #include <string.h>
33 #include <tools/svwin.h>
34 #include <wincomp.hxx>
35 #include <saldata.hxx>
36 #include <salgdi.h>
37 #include <tools/debug.hxx>
38 #include <salframe.h>
39 #include <tools/poly.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <vcl/region.h>
45 using namespace rtl;
47 // =======================================================================
49 // comment out to prevent use of beziers on GDI functions
50 #define USE_GDI_BEZIERS
52 // =======================================================================
54 #define DITHER_PAL_DELTA 51
55 #define DITHER_PAL_STEPS 6
56 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
57 #define DITHER_MAX_SYSCOLOR 16
58 #define DITHER_EXTRA_COLORS 1
59 #define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
61 // =======================================================================
63 struct SysColorEntry
65 DWORD nRGB;
66 SysColorEntry* pNext;
69 // =======================================================================
71 static SysColorEntry* pFirstSysColor = NULL;
72 static SysColorEntry* pActSysColor = NULL;
74 // -----------------------------------------------------------------------------
76 // Blue7
77 static PALETTEENTRY aImplExtraColor1 =
79 0, 184, 255, 0
82 // -----------------------------------------------------------------------------
84 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
86 { 0, 0, 0, 0 },
87 { 0, 0, 0x80, 0 },
88 { 0, 0x80, 0, 0 },
89 { 0, 0x80, 0x80, 0 },
90 { 0x80, 0, 0, 0 },
91 { 0x80, 0, 0x80, 0 },
92 { 0x80, 0x80, 0, 0 },
93 { 0x80, 0x80, 0x80, 0 },
94 { 0xC0, 0xC0, 0xC0, 0 },
95 { 0, 0, 0xFF, 0 },
96 { 0, 0xFF, 0, 0 },
97 { 0, 0xFF, 0xFF, 0 },
98 { 0xFF, 0, 0, 0 },
99 { 0xFF, 0, 0xFF, 0 },
100 { 0xFF, 0xFF, 0, 0 },
101 { 0xFF, 0xFF, 0xFF, 0 }
104 // -----------------------------------------------------------------------------
106 static BYTE aOrdDither8Bit[8][8] =
108 0, 38, 9, 48, 2, 40, 12, 50,
109 25, 12, 35, 22, 28, 15, 37, 24,
110 6, 44, 3, 41, 8, 47, 5, 44,
111 32, 19, 28, 16, 34, 21, 31, 18,
112 1, 40, 11, 49, 0, 39, 10, 48,
113 27, 14, 36, 24, 26, 13, 36, 23,
114 8, 46, 4, 43, 7, 45, 4, 42,
115 33, 20, 30, 17, 32, 20, 29, 16
118 // -----------------------------------------------------------------------------
120 static BYTE aOrdDither16Bit[8][8] =
122 0, 6, 1, 7, 0, 6, 1, 7,
123 4, 2, 5, 3, 4, 2, 5, 3,
124 1, 7, 0, 6, 1, 7, 0, 6,
125 5, 3, 4, 2, 5, 3, 4, 2,
126 0, 6, 1, 7, 0, 6, 1, 7,
127 4, 2, 5, 3, 4, 2, 5, 3,
128 1, 7, 0, 6, 1, 7, 0, 6,
129 5, 3, 4, 2, 5, 3, 4, 2
132 // =======================================================================
134 // Pens muessen wir mit 1 Pixel-Breite erzeugen, da ansonsten die S3-Karte
135 // viele Paintprobleme hat, wenn Polygone/PolyLines gezeichnet werden und
136 // eine komplexe ClipRegion gesetzt ist
137 #define GSL_PEN_WIDTH 1
139 // =======================================================================
141 #define SAL_POLYPOLYCOUNT_STACKBUF 8
142 #define SAL_POLYPOLYPOINTS_STACKBUF 64
144 // =======================================================================
146 void ImplInitSalGDI()
148 SalData* pSalData = GetSalData();
150 // init stock brushes
151 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
152 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
153 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
154 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
155 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
156 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
157 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
158 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
159 pSalData->mnStockPenCount = 4;
161 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
162 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
163 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
164 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
165 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
166 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
167 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
168 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
169 pSalData->mnStockBrushCount = 4;
171 // initialize cache of device contexts
172 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
173 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
175 // initialize temporary font list
176 pSalData->mpTempFontItem = NULL;
178 // support palettes for 256 color displays
179 HDC hDC = GetDC( 0 );
180 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
181 int nPlanes = GetDeviceCaps( hDC, PLANES );
182 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
183 int nBitCount = nBitsPixel * nPlanes;
185 if ( (nBitCount > 8) && (nBitCount < 24) )
187 // test, if we have to dither
188 HDC hMemDC = ::CreateCompatibleDC( hDC );
189 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
190 HBITMAP hBmpOld = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
191 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
192 HBRUSH hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
193 sal_Bool bDither16 = TRUE;
195 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
196 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
198 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
199 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
200 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
201 bDither16 = FALSE;
203 ::SelectObject( hMemDC, hBrushOld ), ::DeleteObject( hMemBrush );
204 ::SelectObject( hMemDC, hBmpOld ), ::DeleteObject( hMemBmp );
205 ::DeleteDC( hMemDC );
207 if( bDither16 )
209 // create DIBPattern for 16Bit dithering
210 long n;
212 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
213 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
214 pSalData->mpDitherDiff = new long[ 256 ];
215 pSalData->mpDitherLow = new BYTE[ 256 ];
216 pSalData->mpDitherHigh = new BYTE[ 256 ];
217 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
218 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
220 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
222 pBIH->biSize = sizeof( BITMAPINFOHEADER );
223 pBIH->biWidth = 8;
224 pBIH->biHeight = 8;
225 pBIH->biPlanes = 1;
226 pBIH->biBitCount = 24;
228 for( n = 0; n < 256L; n++ )
229 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
231 for( n = 0; n < 256L; n++ )
232 pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
234 for( n = 0; n < 256L; n++ )
235 pSalData->mpDitherHigh[ n ] = (BYTE) Min( pSalData->mpDitherLow[ n ] + 8L, 255L );
238 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
240 BYTE nRed, nGreen, nBlue;
241 BYTE nR, nG, nB;
242 PALETTEENTRY* pPalEntry;
243 LOGPALETTE* pLogPal;
244 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
245 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
247 // create logical palette
248 pLogPal = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
249 pLogPal->palVersion = 0x0300;
250 pLogPal->palNumEntries = (sal_uInt16) nTotalCount;
251 pPalEntry = pLogPal->palPalEntry;
253 // Standard colors
254 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
255 pPalEntry += DITHER_MAX_SYSCOLOR;
257 // own palette (6/6/6)
258 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
260 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
262 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
264 pPalEntry->peRed = nRed;
265 pPalEntry->peGreen = nGreen;
266 pPalEntry->peBlue = nBlue;
267 pPalEntry->peFlags = 0;
268 pPalEntry++;
273 // insert special 'Blue' as standard drawing color
274 *pPalEntry++ = aImplExtraColor1;
276 // create palette
277 pSalData->mhDitherPal = CreatePalette( pLogPal );
278 delete[] (char*) pLogPal;
280 if( pSalData->mhDitherPal )
282 // create DIBPattern for 8Bit dithering
283 long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
284 long n;
286 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
287 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
288 pSalData->mpDitherDiff = new long[ 256 ];
289 pSalData->mpDitherLow = new BYTE[ 256 ];
290 pSalData->mpDitherHigh = new BYTE[ 256 ];
291 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
292 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
294 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
295 short* pColors = (short*) ( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
297 pBIH->biSize = sizeof( BITMAPINFOHEADER );
298 pBIH->biWidth = 8;
299 pBIH->biHeight = 8;
300 pBIH->biPlanes = 1;
301 pBIH->biBitCount = 8;
303 for( n = 0; n < nDitherPalCount; n++ )
304 pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
306 for( n = 0; n < 256L; n++ )
307 pSalData->mpDitherDiff[ n ] = n % 51L;
309 for( n = 0; n < 256L; n++ )
310 pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
312 for( n = 0; n < 256L; n++ )
313 pSalData->mpDitherHigh[ n ] = (BYTE)Min( pSalData->mpDitherLow[ n ] + 1, 5 );
316 // get system color entries
317 ImplUpdateSysColorEntries();
320 ReleaseDC( 0, hDC );
323 // -----------------------------------------------------------------------
325 void ImplFreeSalGDI()
327 SalData* pSalData = GetSalData();
329 // destroy stock objects
330 int i;
331 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
332 DeletePen( pSalData->mhStockPenAry[i] );
333 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
334 DeleteBrush( pSalData->mhStockBrushAry[i] );
336 // 50% Brush loeschen
337 if ( pSalData->mh50Brush )
339 DeleteBrush( pSalData->mh50Brush );
340 pSalData->mh50Brush = 0;
343 // 50% Bitmap loeschen
344 if ( pSalData->mh50Bmp )
346 DeleteBitmap( pSalData->mh50Bmp );
347 pSalData->mh50Bmp = 0;
350 ImplClearHDCCache( pSalData );
351 delete[] pSalData->mpHDCCache;
353 // Ditherpalette loeschen, wenn vorhanden
354 if ( pSalData->mhDitherPal )
356 DeleteObject( pSalData->mhDitherPal );
357 pSalData->mhDitherPal = 0;
360 // delete buffers for dithering DIB patterns, if neccessary
361 if ( pSalData->mhDitherDIB )
363 GlobalUnlock( pSalData->mhDitherDIB );
364 GlobalFree( pSalData->mhDitherDIB );
365 pSalData->mhDitherDIB = 0;
366 delete[] pSalData->mpDitherDiff;
367 delete[] pSalData->mpDitherLow;
368 delete[] pSalData->mpDitherHigh;
371 // delete SysColorList
372 SysColorEntry* pEntry = pFirstSysColor;
373 while( pEntry )
375 SysColorEntry* pTmp = pEntry->pNext;
376 delete pEntry;
377 pEntry = pTmp;
379 pFirstSysColor = NULL;
381 // delete icon cache
382 SalIcon* pIcon = pSalData->mpFirstIcon;
383 pSalData->mpFirstIcon = NULL;
384 while( pIcon )
386 SalIcon* pTmp = pIcon->pNext;
387 DestroyIcon( pIcon->hIcon );
388 DestroyIcon( pIcon->hSmallIcon );
389 delete pIcon;
390 pIcon = pTmp;
393 // delete temporary font list
394 ImplReleaseTempFonts( *pSalData );
397 // -----------------------------------------------------------------------
399 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
401 // dither color?
402 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
403 return TRUE;
405 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
407 // standard palette color?
408 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
410 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
411 return TRUE;
414 // extra color?
415 if ( aImplExtraColor1.peRed == nRed &&
416 aImplExtraColor1.peGreen == nGreen &&
417 aImplExtraColor1.peBlue == nBlue )
419 return TRUE;
422 return FALSE;
425 // =======================================================================
427 int ImplIsSysColorEntry( SalColor nSalColor )
429 SysColorEntry* pEntry = pFirstSysColor;
430 const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
431 SALCOLOR_GREEN( nSalColor ),
432 SALCOLOR_BLUE( nSalColor ) );
434 while ( pEntry )
436 if ( pEntry->nRGB == nTestRGB )
437 return TRUE;
438 pEntry = pEntry->pNext;
441 return FALSE;
444 // =======================================================================
446 static void ImplInsertSysColorEntry( int nSysIndex )
448 const DWORD nRGB = GetSysColor( nSysIndex );
450 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
452 if ( !pFirstSysColor )
454 pActSysColor = pFirstSysColor = new SysColorEntry;
455 pFirstSysColor->nRGB = nRGB;
456 pFirstSysColor->pNext = NULL;
458 else
460 pActSysColor = pActSysColor->pNext = new SysColorEntry;
461 pActSysColor->nRGB = nRGB;
462 pActSysColor->pNext = NULL;
467 // =======================================================================
469 void ImplUpdateSysColorEntries()
471 // delete old SysColorList
472 SysColorEntry* pEntry = pFirstSysColor;
473 while( pEntry )
475 SysColorEntry* pTmp = pEntry->pNext;
476 delete pEntry;
477 pEntry = pTmp;
479 pActSysColor = pFirstSysColor = NULL;
481 // create new sys color list
482 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
483 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
484 if( aSalShlData.mnVersion >= 410 )
486 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
487 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
489 ImplInsertSysColorEntry( COLOR_3DFACE );
490 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
491 ImplInsertSysColorEntry( COLOR_3DLIGHT );
492 ImplInsertSysColorEntry( COLOR_3DSHADOW );
493 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
494 ImplInsertSysColorEntry( COLOR_INFOBK );
495 ImplInsertSysColorEntry( COLOR_INFOTEXT );
496 ImplInsertSysColorEntry( COLOR_BTNTEXT );
497 ImplInsertSysColorEntry( COLOR_WINDOW );
498 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
499 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
500 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
501 ImplInsertSysColorEntry( COLOR_MENU );
502 ImplInsertSysColorEntry( COLOR_MENUTEXT );
503 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
504 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
505 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
506 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
509 // -----------------------------------------------------------------------
511 static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
513 SalColor nSalColor;
514 if ( nROPColor == SAL_ROP_0 )
515 nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
516 else
517 nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
518 return nSalColor;
521 // =======================================================================
523 void ImplSalInitGraphics( WinSalGraphics* pData )
525 // Beim Printer berechnen wir die minimale Linienstaerke
526 if ( pData->mbPrinter )
528 int nDPIX = GetDeviceCaps( pData->mhDC, LOGPIXELSX );
529 if ( nDPIX <= 300 )
530 pData->mnPenWidth = 0;
531 else
532 pData->mnPenWidth = nDPIX/300;
535 ::SetTextAlign( pData->mhDC, TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
536 ::SetBkMode( pData->mhDC, TRANSPARENT );
537 ::SetROP2( pData->mhDC, R2_COPYPEN );
540 // -----------------------------------------------------------------------
542 void ImplSalDeInitGraphics( WinSalGraphics* pData )
544 // clear clip region
545 SelectClipRgn( pData->mhDC, 0 );
546 // select default objects
547 if ( pData->mhDefPen )
548 SelectPen( pData->mhDC, pData->mhDefPen );
549 if ( pData->mhDefBrush )
550 SelectBrush( pData->mhDC, pData->mhDefBrush );
551 if ( pData->mhDefFont )
552 SelectFont( pData->mhDC, pData->mhDefFont );
555 // =======================================================================
557 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
559 SalData* pSalData = GetSalData();
560 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
562 if( !pC->mhDC )
564 HDC hDC = GetDC( 0 );
566 // neuen DC mit DefaultBitmap anlegen
567 pC->mhDC = CreateCompatibleDC( hDC );
569 if( pSalData->mhDitherPal )
571 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
572 RealizePalette( pC->mhDC );
575 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
576 pC->mhDefBmp = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
578 ReleaseDC( 0, hDC );
581 if ( hBmp )
582 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
583 else
584 pC->mhActBmp = 0;
586 return pC->mhDC;
589 // =======================================================================
591 void ImplReleaseCachedDC( sal_uLong nID )
593 SalData* pSalData = GetSalData();
594 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
596 if ( pC->mhActBmp )
597 SelectObject( pC->mhDC, pC->mhSelBmp );
600 // =======================================================================
602 void ImplClearHDCCache( SalData* pData )
604 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
606 HDCCache* pC = &pData->mpHDCCache[ i ];
608 if( pC->mhDC )
610 SelectObject( pC->mhDC, pC->mhDefBmp );
612 if( pC->mhDefPal )
613 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
615 DeleteDC( pC->mhDC );
616 DeleteObject( pC->mhSelBmp );
621 // =======================================================================
623 // #100127# Fill point and flag memory from array of points which
624 // might also contain bezier control points for the PolyDraw() GDI method
625 // Make sure pWinPointAry and pWinFlagAry are big enough
626 void ImplPreparePolyDraw( bool bCloseFigures,
627 sal_uLong nPoly,
628 const sal_uLong* pPoints,
629 const SalPoint* const* pPtAry,
630 const BYTE* const* pFlgAry,
631 POINT* pWinPointAry,
632 BYTE* pWinFlagAry )
634 sal_uLong nCurrPoly;
635 for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly )
637 const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ );
638 const BYTE* pCurrFlag = *pFlgAry++;
639 const sal_uLong nCurrPoints = *pPoints++;
640 const bool bHaveFlagArray( pCurrFlag );
641 sal_uLong nCurrPoint;
643 if( nCurrPoints )
645 // start figure
646 *pWinPointAry++ = *pCurrPoint++;
647 *pWinFlagAry++ = PT_MOVETO;
648 ++pCurrFlag;
650 for( nCurrPoint=1; nCurrPoint<nCurrPoints; )
652 // #102067# Check existence of flag array
653 if( bHaveFlagArray &&
654 ( nCurrPoint + 2 ) < nCurrPoints )
656 BYTE P4( pCurrFlag[ 2 ] );
658 if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) &&
659 ( POLY_CONTROL == pCurrFlag[ 1 ] ) &&
660 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
662 // control point one
663 *pWinPointAry++ = *pCurrPoint++;
664 *pWinFlagAry++ = PT_BEZIERTO;
666 // control point two
667 *pWinPointAry++ = *pCurrPoint++;
668 *pWinFlagAry++ = PT_BEZIERTO;
670 // end point
671 *pWinPointAry++ = *pCurrPoint++;
672 *pWinFlagAry++ = PT_BEZIERTO;
674 nCurrPoint += 3;
675 pCurrFlag += 3;
676 continue;
680 // regular line point
681 *pWinPointAry++ = *pCurrPoint++;
682 *pWinFlagAry++ = PT_LINETO;
683 ++pCurrFlag;
684 ++nCurrPoint;
687 // end figure?
688 if( bCloseFigures )
689 pWinFlagAry[-1] |= PT_CLOSEFIGURE;
694 // =======================================================================
696 // #100127# draw an array of points which might also contain bezier control points
697 void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
699 if( nPoints )
701 sal_uInt16 i;
702 // TODO: profile whether the following options are faster:
703 // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
704 // b) convert our flag array to window's and use PolyDraw
706 MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL );
707 ++pPtAry; ++pFlgAry;
709 for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry )
711 if( *pFlgAry != POLY_CONTROL )
713 LineTo( hdc, pPtAry->mnX, pPtAry->mnY );
715 else if( nPoints - i > 2 )
717 PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 );
718 i += 2; pPtAry += 2; pFlgAry += 2;
724 // =======================================================================
726 WinSalGraphics::WinSalGraphics()
728 for( int i = 0; i < MAX_FALLBACK; ++i )
730 mhFonts[ i ] = 0;
731 mpWinFontData[ i ] = NULL;
732 mpWinFontEntry[ i ] = NULL;
735 mfFontScale = 1.0;
737 mhDC = 0;
738 mhPen = 0;
739 mhBrush = 0;
740 mhRegion = 0;
741 mhDefPen = 0;
742 mhDefBrush = 0;
743 mhDefFont = 0;
744 mhDefPal = 0;
745 mpStdClipRgnData = NULL;
746 mpLogFont = NULL;
747 mpFontCharSets = NULL;
748 mpFontAttrCache = NULL;
749 mnFontCharSetCount = 0;
750 mpFontKernPairs = NULL;
751 mnFontKernPairCount = 0;
752 mbFontKernInit = FALSE;
753 mbXORMode = FALSE;
754 mnPenWidth = GSL_PEN_WIDTH;
757 // -----------------------------------------------------------------------
759 WinSalGraphics::~WinSalGraphics()
761 // free obsolete GDI objekts
762 ReleaseFonts();
764 if ( mhPen )
766 if ( !mbStockPen )
767 DeletePen( mhPen );
769 if ( mhBrush )
771 if ( !mbStockBrush )
772 DeleteBrush( mhBrush );
775 if ( mhRegion )
777 DeleteRegion( mhRegion );
778 mhRegion = 0;
781 // Cache-Daten zerstoeren
782 if ( mpStdClipRgnData )
783 delete [] mpStdClipRgnData;
785 if ( mpLogFont )
786 delete mpLogFont;
788 if ( mpFontCharSets )
789 delete mpFontCharSets;
791 if ( mpFontKernPairs )
792 delete mpFontKernPairs;
795 // -----------------------------------------------------------------------
797 void WinSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
799 rDPIX = GetDeviceCaps( mhDC, LOGPIXELSX );
800 rDPIY = GetDeviceCaps( mhDC, LOGPIXELSY );
802 // #111139# this fixes the symptom of div by zero on startup
803 // however, printing will fail most likely as communication with
804 // the printer seems not to work in this case
805 if( !rDPIX || !rDPIY )
806 rDPIX = rDPIY = 600;
809 // -----------------------------------------------------------------------
811 sal_uInt16 WinSalGraphics::GetBitCount()
813 return (sal_uInt16)GetDeviceCaps( mhDC, BITSPIXEL );
816 // -----------------------------------------------------------------------
818 long WinSalGraphics::GetGraphicsWidth() const
820 if( mhWnd && IsWindow( mhWnd ) )
822 WinSalFrame* pFrame = GetWindowPtr( mhWnd );
823 if( pFrame )
825 if( pFrame->maGeometry.nWidth )
826 return pFrame->maGeometry.nWidth;
827 else
829 // TODO: perhaps not needed, maGeometry should always be up-to-date
830 RECT aRect;
831 GetClientRect( mhWnd, &aRect );
832 return aRect.right;
837 return 0;
840 // -----------------------------------------------------------------------
842 void WinSalGraphics::ResetClipRegion()
844 if ( mhRegion )
846 DeleteRegion( mhRegion );
847 mhRegion = 0;
850 SelectClipRgn( mhDC, 0 );
853 // -----------------------------------------------------------------------
855 bool WinSalGraphics::setClipRegion( const Region& i_rClip )
857 if ( mhRegion )
859 DeleteRegion( mhRegion );
860 mhRegion = 0;
863 if( i_rClip.HasPolyPolygon() )
865 // TODO: ConvertToB2DPolyPolygon actually is kind of const, just it does not advertise it in the header
866 basegfx::B2DPolyPolygon aPolyPolygon( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() );
867 const sal_uInt32 nCount(aPolyPolygon.count());
869 if( nCount )
871 std::vector< POINT > aPolyPoints;
872 aPolyPoints.reserve( 1024 );
873 std::vector< INT > aPolyCounts( nCount, 0 );
874 for(sal_uInt32 a(0); a < nCount; a++)
876 basegfx::B2DPolygon aPoly( aPolyPolygon.getB2DPolygon(a) );
877 aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 );
878 const sal_uInt32 nPoints = aPoly.count();
879 aPolyCounts[a] = nPoints;
880 for( sal_uInt32 b = 0; b < nPoints; b++ )
882 basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) );
883 POINT aPOINT;
884 aPOINT.x = (LONG)aPt.getX();
885 aPOINT.y = (LONG)aPt.getY();
886 aPolyPoints.push_back( aPOINT );
889 mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE );
892 else
894 ULONG nRectCount = i_rClip.GetRectCount();
896 ULONG nRectBufSize = sizeof(RECT)*nRectCount;
897 if ( nRectCount < SAL_CLIPRECT_COUNT )
899 if ( !mpStdClipRgnData )
900 mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
901 mpClipRgnData = mpStdClipRgnData;
903 else
904 mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
905 mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
906 mpClipRgnData->rdh.iType = RDH_RECTANGLES;
907 mpClipRgnData->rdh.nCount = nRectCount;
908 mpClipRgnData->rdh.nRgnSize = nRectBufSize;
909 RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
910 SetRectEmpty( pBoundRect );
911 RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
912 bool bFirstClipRect = true;
914 ImplRegionInfo aInfo;
915 long nX, nY, nW, nH;
916 bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
917 while( bRegionRect )
919 if ( nW && nH )
921 long nRight = nX + nW;
922 long nBottom = nY + nH;
924 if ( bFirstClipRect )
926 pBoundRect->left = nX;
927 pBoundRect->top = nY;
928 pBoundRect->right = nRight;
929 pBoundRect->bottom = nBottom;
930 bFirstClipRect = false;
932 else
934 if ( nX < pBoundRect->left )
935 pBoundRect->left = (int)nX;
937 if ( nY < pBoundRect->top )
938 pBoundRect->top = (int)nY;
940 if ( nRight > pBoundRect->right )
941 pBoundRect->right = (int)nRight;
943 if ( nBottom > pBoundRect->bottom )
944 pBoundRect->bottom = (int)nBottom;
947 pNextClipRect->left = (int)nX;
948 pNextClipRect->top = (int)nY;
949 pNextClipRect->right = (int)nRight;
950 pNextClipRect->bottom = (int)nBottom;
951 pNextClipRect++;
953 else
955 mpClipRgnData->rdh.nCount--;
956 mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
958 bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
960 // create clip region from ClipRgnData
961 if ( mpClipRgnData->rdh.nCount == 1 )
963 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
964 mhRegion = CreateRectRgn( pRect->left, pRect->top,
965 pRect->right, pRect->bottom );
967 else if( mpClipRgnData->rdh.nCount > 1 )
969 ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
970 mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
972 // if ExtCreateRegion(...) is not supported
973 if( !mhRegion )
975 RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData;
977 if( pHeader->nCount )
979 RECT* pRect = (RECT*) mpClipRgnData->Buffer;
980 mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
981 pRect++;
983 for( ULONG n = 1; n < pHeader->nCount; n++, pRect++ )
985 HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
986 CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR );
987 DeleteRegion( hRgn );
992 if ( mpClipRgnData != mpStdClipRgnData )
993 delete [] mpClipRgnData;
997 if( mhRegion )
998 SelectClipRgn( mhDC, mhRegion );
999 return mhRegion != 0;
1002 // -----------------------------------------------------------------------
1004 void WinSalGraphics::SetLineColor()
1006 // create and select new pen
1007 HPEN hNewPen = GetStockPen( NULL_PEN );
1008 HPEN hOldPen = SelectPen( mhDC, hNewPen );
1010 // destory or save old pen
1011 if ( mhPen )
1013 if ( !mbStockPen )
1014 DeletePen( mhPen );
1016 else
1017 mhDefPen = hOldPen;
1019 // set new data
1020 mhPen = hNewPen;
1021 mbPen = FALSE;
1022 mbStockPen = TRUE;
1025 // -----------------------------------------------------------------------
1027 void WinSalGraphics::SetLineColor( SalColor nSalColor )
1029 maLineColor = nSalColor;
1030 COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
1031 SALCOLOR_GREEN( nSalColor ),
1032 SALCOLOR_BLUE( nSalColor ) );
1033 HPEN hNewPen = 0;
1034 sal_Bool bStockPen = FALSE;
1036 // search for stock pen (only screen, because printer have problems,
1037 // when we use stock objects)
1038 if ( !mbPrinter )
1040 SalData* pSalData = GetSalData();
1041 for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ )
1043 if ( nPenColor == pSalData->maStockPenColorAry[i] )
1045 hNewPen = pSalData->mhStockPenAry[i];
1046 bStockPen = TRUE;
1047 break;
1052 // create new pen
1053 if ( !hNewPen )
1055 if ( !mbPrinter )
1057 if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
1058 nPenColor = PALRGB_TO_RGB( nPenColor );
1061 hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor );
1062 bStockPen = FALSE;
1065 // select new pen
1066 HPEN hOldPen = SelectPen( mhDC, hNewPen );
1068 // destory or save old pen
1069 if ( mhPen )
1071 if ( !mbStockPen )
1072 DeletePen( mhPen );
1074 else
1075 mhDefPen = hOldPen;
1077 // set new data
1078 mnPenColor = nPenColor;
1079 mhPen = hNewPen;
1080 mbPen = TRUE;
1081 mbStockPen = bStockPen;
1084 // -----------------------------------------------------------------------
1086 void WinSalGraphics::SetFillColor()
1088 // create and select new brush
1089 HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
1090 HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
1092 // destory or save old brush
1093 if ( mhBrush )
1095 if ( !mbStockBrush )
1096 DeleteBrush( mhBrush );
1098 else
1099 mhDefBrush = hOldBrush;
1101 // set new data
1102 mhBrush = hNewBrush;
1103 mbBrush = FALSE;
1104 mbStockBrush = TRUE;
1107 // -----------------------------------------------------------------------
1109 void WinSalGraphics::SetFillColor( SalColor nSalColor )
1111 maFillColor = nSalColor;
1112 SalData* pSalData = GetSalData();
1113 BYTE nRed = SALCOLOR_RED( nSalColor );
1114 BYTE nGreen = SALCOLOR_GREEN( nSalColor );
1115 BYTE nBlue = SALCOLOR_BLUE( nSalColor );
1116 COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue );
1117 HBRUSH hNewBrush = 0;
1118 sal_Bool bStockBrush = FALSE;
1120 // search for stock brush (only screen, because printer have problems,
1121 // when we use stock objects)
1122 if ( !mbPrinter )
1124 for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ )
1126 if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] )
1128 hNewBrush = pSalData->mhStockBrushAry[i];
1129 bStockBrush = TRUE;
1130 break;
1135 // create new brush
1136 if ( !hNewBrush )
1138 if ( mbPrinter || !pSalData->mhDitherDIB )
1139 hNewBrush = CreateSolidBrush( nBrushColor );
1140 else
1142 if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount )
1144 BYTE* pTmp = pSalData->mpDitherDIBData;
1145 long* pDitherDiff = pSalData->mpDitherDiff;
1146 BYTE* pDitherLow = pSalData->mpDitherLow;
1147 BYTE* pDitherHigh = pSalData->mpDitherHigh;
1149 for( long nY = 0L; nY < 8L; nY++ )
1151 for( long nX = 0L; nX < 8L; nX++ )
1153 const long nThres = aOrdDither16Bit[ nY ][ nX ];
1154 *pTmp++ = DMAP( nBlue, nThres );
1155 *pTmp++ = DMAP( nGreen, nThres );
1156 *pTmp++ = DMAP( nRed, nThres );
1160 hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS );
1162 else if ( ImplIsSysColorEntry( nSalColor ) )
1164 nBrushColor = PALRGB_TO_RGB( nBrushColor );
1165 hNewBrush = CreateSolidBrush( nBrushColor );
1167 else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) )
1168 hNewBrush = CreateSolidBrush( nBrushColor );
1169 else
1171 BYTE* pTmp = pSalData->mpDitherDIBData;
1172 long* pDitherDiff = pSalData->mpDitherDiff;
1173 BYTE* pDitherLow = pSalData->mpDitherLow;
1174 BYTE* pDitherHigh = pSalData->mpDitherHigh;
1176 for ( long nY = 0L; nY < 8L; nY++ )
1178 for ( long nX = 0L; nX < 8L; nX++ )
1180 const long nThres = aOrdDither8Bit[ nY ][ nX ];
1181 *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36;
1182 pTmp++;
1186 hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
1190 bStockBrush = FALSE;
1193 // select new brush
1194 HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
1196 // destory or save old brush
1197 if ( mhBrush )
1199 if ( !mbStockBrush )
1200 DeleteBrush( mhBrush );
1202 else
1203 mhDefBrush = hOldBrush;
1205 // set new data
1206 mnBrushColor = nBrushColor;
1207 mhBrush = hNewBrush;
1208 mbBrush = TRUE;
1209 mbStockBrush = bStockBrush;
1212 // -----------------------------------------------------------------------
1214 void WinSalGraphics::SetXORMode( bool bSet, bool )
1216 mbXORMode = bSet;
1217 ::SetROP2( mhDC, bSet ? R2_XORPEN : R2_COPYPEN );
1220 // -----------------------------------------------------------------------
1222 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
1224 SetLineColor( ImplGetROPSalColor( nROPColor ) );
1227 // -----------------------------------------------------------------------
1229 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
1231 SetFillColor( ImplGetROPSalColor( nROPColor ) );
1234 // -----------------------------------------------------------------------
1236 void WinSalGraphics::drawPixel( long nX, long nY )
1238 if ( mbXORMode )
1240 HBRUSH hBrush = CreateSolidBrush( mnPenColor );
1241 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1242 PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1243 SelectBrush( mhDC, hOldBrush );
1244 DeleteBrush( hBrush );
1246 else
1247 SetPixel( mhDC, (int)nX, (int)nY, mnPenColor );
1250 // -----------------------------------------------------------------------
1252 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
1254 COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1255 SALCOLOR_GREEN( nSalColor ),
1256 SALCOLOR_BLUE( nSalColor ) );
1258 if ( !mbPrinter &&
1259 GetSalData()->mhDitherPal &&
1260 ImplIsSysColorEntry( nSalColor ) )
1261 nCol = PALRGB_TO_RGB( nCol );
1263 if ( mbXORMode )
1265 HBRUSH hBrush = CreateSolidBrush( nCol );
1266 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1267 PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1268 SelectBrush( mhDC, hOldBrush );
1269 DeleteBrush( hBrush );
1271 else
1272 ::SetPixel( mhDC, (int)nX, (int)nY, nCol );
1275 // -----------------------------------------------------------------------
1277 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
1279 MoveToEx( mhDC, (int)nX1, (int)nY1, NULL );
1281 // we must paint the endpoint
1282 int bPaintEnd = TRUE;
1283 if ( nX1 == nX2 )
1285 bPaintEnd = FALSE;
1286 if ( nY1 <= nY2 )
1287 nY2++;
1288 else
1289 nY2--;
1291 if ( nY1 == nY2 )
1293 bPaintEnd = FALSE;
1294 if ( nX1 <= nX2 )
1295 nX2++;
1296 else
1297 nX2--;
1300 LineTo( mhDC, (int)nX2, (int)nY2 );
1302 if ( bPaintEnd && !mbPrinter )
1304 if ( mbXORMode )
1306 HBRUSH hBrush = CreateSolidBrush( mnPenColor );
1307 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1308 PatBlt( mhDC, (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
1309 SelectBrush( mhDC, hOldBrush );
1310 DeleteBrush( hBrush );
1312 else
1313 SetPixel( mhDC, (int)nX2, (int)nY2, mnPenColor );
1317 // -----------------------------------------------------------------------
1319 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
1321 if ( !mbPen )
1323 if ( !mbPrinter )
1325 PatBlt( mhDC, (int)nX, (int)nY, (int)nWidth, (int)nHeight,
1326 mbXORMode ? PATINVERT : PATCOPY );
1328 else
1330 RECT aWinRect;
1331 aWinRect.left = nX;
1332 aWinRect.top = nY;
1333 aWinRect.right = nX+nWidth;
1334 aWinRect.bottom = nY+nHeight;
1335 ::FillRect( mhDC, &aWinRect, mhBrush );
1338 else
1339 WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
1342 // -----------------------------------------------------------------------
1344 void WinSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry )
1346 // Unter NT koennen wir das Array direkt weiterreichen
1347 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1348 "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
1350 POINT* pWinPtAry = (POINT*)pPtAry;
1351 // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1352 // von Punkten
1353 if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1354 Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
1357 // -----------------------------------------------------------------------
1359 void WinSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
1361 // Unter NT koennen wir das Array direkt weiterreichen
1362 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1363 "WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
1365 POINT* pWinPtAry = (POINT*)pPtAry;
1366 // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1367 // von Punkten
1368 if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1369 WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
1372 // -----------------------------------------------------------------------
1374 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1375 PCONSTSALPOINT* pPtAry )
1377 UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF];
1378 UINT* pWinPointAry;
1379 UINT nPolyPolyPoints = 0;
1380 UINT nPoints;
1381 UINT i;
1383 if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
1384 pWinPointAry = aWinPointAry;
1385 else
1386 pWinPointAry = new UINT[nPoly];
1388 for ( i = 0; i < (UINT)nPoly; i++ )
1390 nPoints = (UINT)pPoints[i]+1;
1391 pWinPointAry[i] = nPoints;
1392 nPolyPolyPoints += nPoints;
1395 POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF];
1396 POINT* pWinPointAryAry;
1397 if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF )
1398 pWinPointAryAry = aWinPointAryAry;
1399 else
1400 pWinPointAryAry = new POINT[nPolyPolyPoints];
1401 // Unter NT koennen wir das Array direkt weiterreichen
1402 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1403 "WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" );
1404 const SalPoint* pPolyAry;
1405 UINT n = 0;
1406 for ( i = 0; i < (UINT)nPoly; i++ )
1408 nPoints = pWinPointAry[i];
1409 pPolyAry = pPtAry[i];
1410 memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) );
1411 pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n];
1412 n += nPoints;
1415 if ( !WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
1416 (nPolyPolyPoints > MAX_64KSALPOINTS) )
1418 nPolyPolyPoints = 0;
1419 nPoly = 0;
1422 nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
1423 nPoly++;
1425 while ( nPolyPolyPoints < MAX_64KSALPOINTS );
1426 nPoly--;
1427 if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
1428 pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
1429 if ( nPoly == 1 )
1430 WIN_Polygon( mhDC, pWinPointAryAry, *pWinPointAry );
1431 else
1432 WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, nPoly );
1435 if ( pWinPointAry != aWinPointAry )
1436 delete [] pWinPointAry;
1437 if ( pWinPointAryAry != aWinPointAryAry )
1438 delete [] pWinPointAryAry;
1441 // -----------------------------------------------------------------------
1443 #define SAL_POLY_STACKBUF 32
1445 // -----------------------------------------------------------------------
1447 sal_Bool WinSalGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1449 #ifdef USE_GDI_BEZIERS
1450 // Unter NT koennen wir das Array direkt weiterreichen
1451 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1452 "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
1454 ImplRenderPath( mhDC, nPoints, pPtAry, pFlgAry );
1456 return sal_True;
1457 #else
1458 return sal_False;
1459 #endif
1462 // -----------------------------------------------------------------------
1464 sal_Bool WinSalGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1466 #ifdef USE_GDI_BEZIERS
1467 // Unter NT koennen wir das Array direkt weiterreichen
1468 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1469 "WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" );
1471 POINT aStackAry1[SAL_POLY_STACKBUF];
1472 BYTE aStackAry2[SAL_POLY_STACKBUF];
1473 POINT* pWinPointAry;
1474 BYTE* pWinFlagAry;
1475 if( nPoints > SAL_POLY_STACKBUF )
1477 pWinPointAry = new POINT[ nPoints ];
1478 pWinFlagAry = new BYTE[ nPoints ];
1480 else
1482 pWinPointAry = aStackAry1;
1483 pWinFlagAry = aStackAry2;
1486 ImplPreparePolyDraw(true, 1, &nPoints, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
1488 sal_Bool bRet( sal_False );
1490 if( BeginPath( mhDC ) )
1492 PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nPoints);
1494 if( EndPath( mhDC ) )
1496 if( StrokeAndFillPath( mhDC ) )
1497 bRet = sal_True;
1501 if( pWinPointAry != aStackAry1 )
1503 delete [] pWinPointAry;
1504 delete [] pWinFlagAry;
1507 return bRet;
1508 #else
1509 return sal_False;
1510 #endif
1513 // -----------------------------------------------------------------------
1515 sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1516 const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
1518 #ifdef USE_GDI_BEZIERS
1519 // Unter NT koennen wir das Array direkt weiterreichen
1520 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1521 "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
1523 sal_uLong nCurrPoly, nTotalPoints;
1524 const sal_uLong* pCurrPoints = pPoints;
1525 for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
1526 nTotalPoints += *pCurrPoints++;
1528 POINT aStackAry1[SAL_POLY_STACKBUF];
1529 BYTE aStackAry2[SAL_POLY_STACKBUF];
1530 POINT* pWinPointAry;
1531 BYTE* pWinFlagAry;
1532 if( nTotalPoints > SAL_POLY_STACKBUF )
1534 pWinPointAry = new POINT[ nTotalPoints ];
1535 pWinFlagAry = new BYTE[ nTotalPoints ];
1537 else
1539 pWinPointAry = aStackAry1;
1540 pWinFlagAry = aStackAry2;
1543 ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
1545 sal_Bool bRet( sal_False );
1547 if( BeginPath( mhDC ) )
1549 PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nTotalPoints);
1551 if( EndPath( mhDC ) )
1553 if( StrokeAndFillPath( mhDC ) )
1554 bRet = sal_True;
1558 if( pWinPointAry != aStackAry1 )
1560 delete [] pWinPointAry;
1561 delete [] pWinFlagAry;
1564 return bRet;
1565 #else
1566 return sal_False;
1567 #endif
1570 // -----------------------------------------------------------------------
1572 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
1573 #define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
1574 // in the first 4096 bytes
1576 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize )
1578 while ( nComp-- >= nSize )
1580 sal_uLong i;
1581 for ( i = 0; i < nSize; i++ )
1583 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
1584 break;
1586 if ( i == nSize )
1587 return pSource;
1588 pSource++;
1590 return NULL;
1593 static sal_Bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
1595 sal_Bool bRetValue = FALSE;
1596 BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
1597 if ( pDest )
1599 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
1600 pDest += 14;
1602 int nSizeLeft = nSize - ( pDest - pSource );
1603 if ( nSizeLeft > 100 )
1604 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
1606 int i;
1607 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
1609 int nDivision = 1;
1610 sal_Bool bDivision = FALSE;
1611 sal_Bool bNegative = FALSE;
1612 sal_Bool bValid = TRUE;
1614 while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
1615 BYTE nByte = *pDest;
1616 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
1618 switch ( nByte )
1620 case '.' :
1621 if ( bDivision )
1622 bValid = FALSE;
1623 else
1624 bDivision = TRUE;
1625 break;
1626 case '-' :
1627 bNegative = TRUE;
1628 break;
1629 default :
1630 if ( ( nByte < '0' ) || ( nByte > '9' ) )
1631 nSizeLeft = 1; // error parsing the bounding box values
1632 else if ( bValid )
1634 if ( bDivision )
1635 nDivision*=10;
1636 nNumb[i] *= 10;
1637 nNumb[i] += nByte - '0';
1639 break;
1641 nSizeLeft--;
1642 nByte = *(++pDest);
1644 if ( bNegative )
1645 nNumb[i] = -nNumb[i];
1646 if ( bDivision && ( nDivision != 1 ) )
1647 nNumb[i] /= nDivision;
1649 if ( i == 4 )
1650 bRetValue = TRUE;
1652 return bRetValue;
1655 sal_Bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
1657 sal_Bool bRetValue = FALSE;
1659 if ( mbPrinter )
1661 int nEscape = POSTSCRIPT_PASSTHROUGH;
1663 if ( Escape( mhDC, QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
1665 double nBoundingBox[4];
1667 if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
1669 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1671 // reserve place for a sal_uInt16
1672 aBuf.append( "aa" );
1674 // #107797# Write out EPS encapsulation header
1675 // ----------------------------------------------------------------------------------
1677 // directly taken from the PLRM 3.0, p. 726. Note:
1678 // this will definitely cause problems when
1679 // recursively creating and embedding PostScript files
1680 // in OOo, since we use statically-named variables
1681 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1682 // op_count_salWin). Currently, I have no idea on how to
1683 // work around that, except from scanning and
1684 // interpreting the EPS for unused identifiers.
1686 // append the real text
1687 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1688 "/dict_count_salWin countdictstack def\n"
1689 "/op_count_salWin count 1 sub def\n"
1690 "userdict begin\n"
1691 "/showpage {} def\n"
1692 "0 setgray 0 setlinecap\n"
1693 "1 setlinewidth 0 setlinejoin\n"
1694 "10 setmiterlimit [] 0 setdash newpath\n"
1695 "/languagelevel where\n"
1696 "{\n"
1697 " pop languagelevel\n"
1698 " 1 ne\n"
1699 " {\n"
1700 " false setstrokeadjust false setoverprint\n"
1701 " } if\n"
1702 "} if\n\n" );
1705 // #i10737# Apply clipping manually
1706 // ----------------------------------------------------------------------------------
1708 // Windows seems to ignore any clipping at the HDC,
1709 // when followed by a POSTSCRIPT_PASSTHROUGH
1711 // Check whether we've got a clipping, consisting of
1712 // exactly one rect (other cases should be, but aren't
1713 // handled currently)
1715 // TODO: Handle more than one rectangle here (take
1716 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1717 // characters!)
1718 if ( mhRegion != 0 &&
1719 mpStdClipRgnData != NULL &&
1720 mpClipRgnData == mpStdClipRgnData &&
1721 mpClipRgnData->rdh.nCount == 1 )
1723 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1725 aBuf.append( "\nnewpath\n" );
1726 aBuf.append( pRect->left );
1727 aBuf.append( " " );
1728 aBuf.append( pRect->top );
1729 aBuf.append( " moveto\n" );
1730 aBuf.append( pRect->right );
1731 aBuf.append( " " );
1732 aBuf.append( pRect->top );
1733 aBuf.append( " lineto\n" );
1734 aBuf.append( pRect->right );
1735 aBuf.append( " " );
1736 aBuf.append( pRect->bottom );
1737 aBuf.append( " lineto\n" );
1738 aBuf.append( pRect->left );
1739 aBuf.append( " " );
1740 aBuf.append( pRect->bottom );
1741 aBuf.append( " lineto\n"
1742 "closepath\n"
1743 "clip\n"
1744 "newpath\n" );
1747 // #107797# Write out buffer
1748 // ----------------------------------------------------------------------------------
1749 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1750 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1753 // #107797# Write out EPS transformation code
1754 // ----------------------------------------------------------------------------------
1755 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1756 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1757 // reserve a sal_uInt16 again
1758 aBuf.setLength( 2 );
1759 aBuf.append( "\n\n[" );
1760 aBuf.append( dM11 );
1761 aBuf.append( " 0 0 " );
1762 aBuf.append( dM22 );
1763 aBuf.append( ' ' );
1764 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1765 aBuf.append( ' ' );
1766 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1767 aBuf.append( "] concat\n"
1768 "%%BeginDocument:\n" );
1769 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1770 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1773 // #107797# Write out actual EPS content
1774 // ----------------------------------------------------------------------------------
1775 sal_uLong nToDo = nSize;
1776 sal_uLong nDoNow;
1777 while ( nToDo )
1779 nDoNow = nToDo;
1780 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1781 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1782 // the following is based on the string buffer allocation
1783 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1784 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
1785 memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
1786 sal_uLong nResult = Escape ( mhDC, nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
1787 if (!nResult )
1788 break;
1789 nToDo -= nResult;
1793 // #107797# Write out EPS encapsulation footer
1794 // ----------------------------------------------------------------------------------
1795 // reserve a sal_uInt16 again
1796 aBuf.setLength( 2 );
1797 aBuf.append( "%%EndDocument\n"
1798 "count op_count_salWin sub {pop} repeat\n"
1799 "countdictstack dict_count_salWin sub {end} repeat\n"
1800 "b4_Inc_state_salWin restore\n\n" );
1801 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1802 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1803 bRetValue = TRUE;
1808 return bRetValue;
1811 // -----------------------------------------------------------------------
1813 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1815 SystemGraphicsData aRes;
1816 aRes.nSize = sizeof(aRes);
1817 aRes.hDC = mhDC;
1818 return aRes;
1821 // -----------------------------------------------------------------------