xref: /AOO41X/main/vcl/win/source/gdi/salgdi.cxx (revision a27c4c8a140a5e43ed93b28e87d055916a53c3a3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include <rtl/strbuf.hxx>
31 
32 #include <tools/svwin.h>
33 #include <tools/debug.hxx>
34 #include <tools/poly.hxx>
35 
36 #include <basegfx/polygon/b2dpolygon.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 
39 #include <win/wincomp.hxx>
40 #include <win/saldata.hxx>
41 #include <win/salgdi.h>
42 #include <win/salframe.h>
43 
44 using namespace rtl;
45 
46 // =======================================================================
47 
48 // comment out to prevent use of beziers on GDI functions
49 #define USE_GDI_BEZIERS
50 
51 // =======================================================================
52 
53 #define DITHER_PAL_DELTA				51
54 #define DITHER_PAL_STEPS				6
55 #define DITHER_PAL_COUNT				(DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
56 #define DITHER_MAX_SYSCOLOR 			16
57 #define DITHER_EXTRA_COLORS 			1
58 #define DMAP( _def_nVal, _def_nThres )	((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
59 
60 // =======================================================================
61 
62 struct SysColorEntry
63 {
64 	DWORD			nRGB;
65 	SysColorEntry*	pNext;
66 };
67 
68 // =======================================================================
69 
70 static SysColorEntry* pFirstSysColor = NULL;
71 static SysColorEntry* pActSysColor = NULL;
72 
73 // -----------------------------------------------------------------------------
74 
75 // Blue7
76 static PALETTEENTRY aImplExtraColor1 =
77 {
78 	0, 184, 255, 0
79 };
80 
81 // -----------------------------------------------------------------------------
82 
83 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
84 {
85 {	 0,    0,	 0, 0 },
86 {	 0,    0, 0x80, 0 },
87 {	 0, 0x80,	 0, 0 },
88 {	 0, 0x80, 0x80, 0 },
89 { 0x80,    0,	 0, 0 },
90 { 0x80,    0, 0x80, 0 },
91 { 0x80, 0x80,	 0, 0 },
92 { 0x80, 0x80, 0x80, 0 },
93 { 0xC0, 0xC0, 0xC0, 0 },
94 {	 0,    0, 0xFF, 0 },
95 {	 0, 0xFF,	 0, 0 },
96 {	 0, 0xFF, 0xFF, 0 },
97 { 0xFF,    0,	 0, 0 },
98 { 0xFF,    0, 0xFF, 0 },
99 { 0xFF, 0xFF,	 0, 0 },
100 { 0xFF, 0xFF, 0xFF, 0 }
101 };
102 
103 // -----------------------------------------------------------------------------
104 
105 static BYTE aOrdDither8Bit[8][8] =
106 {
107 	 0, 38,  9, 48,  2, 40, 12, 50,
108 	25, 12, 35, 22, 28, 15, 37, 24,
109 	 6, 44,  3, 41,  8, 47,  5, 44,
110 	32, 19, 28, 16, 34, 21, 31, 18,
111 	 1, 40, 11, 49,  0, 39, 10, 48,
112 	27, 14, 36, 24, 26, 13, 36, 23,
113 	 8, 46,  4, 43,  7, 45,  4, 42,
114 	33, 20, 30, 17, 32, 20, 29, 16
115 };
116 
117 // -----------------------------------------------------------------------------
118 
119 static BYTE aOrdDither16Bit[8][8] =
120 {
121 	0, 6, 1, 7, 0, 6, 1, 7,
122 	4, 2, 5, 3, 4, 2, 5, 3,
123 	1, 7, 0, 6, 1, 7, 0, 6,
124 	5, 3, 4, 2, 5, 3, 4, 2,
125 	0, 6, 1, 7, 0, 6, 1, 7,
126 	4, 2, 5, 3, 4, 2, 5, 3,
127 	1, 7, 0, 6, 1, 7, 0, 6,
128 	5, 3, 4, 2, 5, 3, 4, 2
129 };
130 
131 // =======================================================================
132 
133 // Pens muessen wir mit 1 Pixel-Breite erzeugen, da ansonsten die S3-Karte
134 // viele Paintprobleme hat, wenn Polygone/PolyLines gezeichnet werden und
135 // eine komplexe ClipRegion gesetzt ist
136 #define GSL_PEN_WIDTH					1
137 
138 // =======================================================================
139 
140 #define SAL_POLYPOLYCOUNT_STACKBUF			8
141 #define SAL_POLYPOLYPOINTS_STACKBUF 		64
142 
143 // =======================================================================
144 
145 void ImplInitSalGDI()
146 {
147 	SalData* pSalData = GetSalData();
148 
149 	// init stock brushes
150 	pSalData->maStockPenColorAry[0] 	= PALETTERGB( 0, 0, 0 );
151 	pSalData->maStockPenColorAry[1] 	= PALETTERGB( 0xFF, 0xFF, 0xFF );
152 	pSalData->maStockPenColorAry[2] 	= PALETTERGB( 0xC0, 0xC0, 0xC0 );
153 	pSalData->maStockPenColorAry[3] 	= PALETTERGB( 0x80, 0x80, 0x80 );
154 	pSalData->mhStockPenAry[0]			= CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
155 	pSalData->mhStockPenAry[1]			= CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
156 	pSalData->mhStockPenAry[2]			= CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
157 	pSalData->mhStockPenAry[3]			= CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
158 	pSalData->mnStockPenCount = 4;
159 
160 	pSalData->maStockBrushColorAry[0]	= PALETTERGB( 0, 0, 0 );
161 	pSalData->maStockBrushColorAry[1]	= PALETTERGB( 0xFF, 0xFF, 0xFF );
162 	pSalData->maStockBrushColorAry[2]	= PALETTERGB( 0xC0, 0xC0, 0xC0 );
163 	pSalData->maStockBrushColorAry[3]	= PALETTERGB( 0x80, 0x80, 0x80 );
164 	pSalData->mhStockBrushAry[0]		= CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
165 	pSalData->mhStockBrushAry[1]		= CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
166 	pSalData->mhStockBrushAry[2]		= CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
167 	pSalData->mhStockBrushAry[3]		= CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
168 	pSalData->mnStockBrushCount = 4;
169 
170 	// initialize cache of device contexts
171 	pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
172 	memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
173 
174     // initialize temporary font list
175     pSalData->mpTempFontItem = NULL;
176 
177 	// support palettes for 256 color displays
178 	HDC hDC = GetDC( 0 );
179 	int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
180 	int nPlanes = GetDeviceCaps( hDC, PLANES );
181 	int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
182 	int nBitCount = nBitsPixel * nPlanes;
183 
184 	if ( (nBitCount > 8) && (nBitCount < 24) )
185 	{
186 		// test, if we have to dither
187 		HDC 		hMemDC = ::CreateCompatibleDC( hDC );
188 		HBITMAP 	hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
189 		HBITMAP 	hBmpOld = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
190 		HBRUSH		hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
191 		HBRUSH		hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
192 		sal_Bool		bDither16 = TRUE;
193 
194 		::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
195 		const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
196 
197 		for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
198 			for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
199 				if( ::GetPixel( hMemDC, nX, nY ) != aCol )
200 					bDither16 = FALSE;
201 
202 		::SelectObject( hMemDC, hBrushOld ), ::DeleteObject( hMemBrush );
203 		::SelectObject( hMemDC, hBmpOld ), ::DeleteObject( hMemBmp );
204 		::DeleteDC( hMemDC );
205 
206 		if( bDither16 )
207 		{
208 			// create DIBPattern for 16Bit dithering
209 			long n;
210 
211 			pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
212 			pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
213 			pSalData->mpDitherDiff = new long[ 256 ];
214 			pSalData->mpDitherLow = new BYTE[ 256 ];
215 			pSalData->mpDitherHigh = new BYTE[ 256 ];
216 			pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
217 			memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
218 
219 			BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
220 
221 			pBIH->biSize = sizeof( BITMAPINFOHEADER );
222 			pBIH->biWidth = 8;
223 			pBIH->biHeight = 8;
224 			pBIH->biPlanes = 1;
225 			pBIH->biBitCount = 24;
226 
227 			for( n = 0; n < 256L; n++ )
228 				pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
229 
230 			for( n = 0; n < 256L; n++ )
231 				pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
232 
233 			for( n = 0; n < 256L; n++ )
234 				pSalData->mpDitherHigh[ n ] = (BYTE) Min( pSalData->mpDitherLow[ n ] + 8L, 255L );
235 		}
236 	}
237 	else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
238 	{
239 		BYTE			nRed, nGreen, nBlue;
240 		BYTE			nR, nG, nB;
241 		PALETTEENTRY*	pPalEntry;
242 		LOGPALETTE* 	pLogPal;
243 		const sal_uInt16	nDitherPalCount = DITHER_PAL_COUNT;
244 		sal_uLong			nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
245 
246 		// create logical palette
247 		pLogPal = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
248 		pLogPal->palVersion = 0x0300;
249 		pLogPal->palNumEntries = (sal_uInt16) nTotalCount;
250 		pPalEntry = pLogPal->palPalEntry;
251 
252 		// Standard colors
253 		memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
254 		pPalEntry += DITHER_MAX_SYSCOLOR;
255 
256 		// own palette (6/6/6)
257 		for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
258 		{
259 			for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
260 			{
261 				for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
262 				{
263 					pPalEntry->peRed   = nRed;
264 					pPalEntry->peGreen = nGreen;
265 					pPalEntry->peBlue  = nBlue;
266 					pPalEntry->peFlags = 0;
267 					pPalEntry++;
268 				}
269 			}
270 		}
271 
272 		// insert special 'Blue' as standard drawing color
273 		*pPalEntry++ = aImplExtraColor1;
274 
275 		// create palette
276 		pSalData->mhDitherPal = CreatePalette( pLogPal );
277 		delete[] (char*) pLogPal;
278 
279 		if( pSalData->mhDitherPal )
280 		{
281 			// create DIBPattern for 8Bit dithering
282 			long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
283 			long n;
284 
285 			pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
286 			pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
287 			pSalData->mpDitherDiff = new long[ 256 ];
288 			pSalData->mpDitherLow = new BYTE[ 256 ];
289 			pSalData->mpDitherHigh = new BYTE[ 256 ];
290 			pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
291 			memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
292 
293 			BITMAPINFOHEADER*	pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
294 			short*				pColors = (short*) ( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
295 
296 			pBIH->biSize = sizeof( BITMAPINFOHEADER );
297 			pBIH->biWidth = 8;
298 			pBIH->biHeight = 8;
299 			pBIH->biPlanes = 1;
300 			pBIH->biBitCount = 8;
301 
302 			for( n = 0; n < nDitherPalCount; n++ )
303 				pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
304 
305 			for( n = 0; n < 256L; n++ )
306 				pSalData->mpDitherDiff[ n ] = n % 51L;
307 
308 			for( n = 0; n < 256L; n++ )
309 				pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
310 
311 			for( n = 0; n < 256L; n++ )
312 				pSalData->mpDitherHigh[ n ] = (BYTE)Min( pSalData->mpDitherLow[ n ] + 1, 5 );
313 		}
314 
315 		// get system color entries
316 		ImplUpdateSysColorEntries();
317 	}
318 
319 	ReleaseDC( 0, hDC );
320 }
321 
322 // -----------------------------------------------------------------------
323 
324 void ImplFreeSalGDI()
325 {
326 	SalData*	pSalData = GetSalData();
327 
328 	// destroy stock objects
329 	int	i;
330 	for ( i = 0; i < pSalData->mnStockPenCount; i++ )
331 		DeletePen( pSalData->mhStockPenAry[i] );
332 	for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
333 		DeleteBrush( pSalData->mhStockBrushAry[i] );
334 
335 	// 50% Brush loeschen
336 	if ( pSalData->mh50Brush )
337 	{
338 		DeleteBrush( pSalData->mh50Brush );
339 		pSalData->mh50Brush = 0;
340 	}
341 
342 	// 50% Bitmap loeschen
343 	if ( pSalData->mh50Bmp )
344 	{
345 		DeleteBitmap( pSalData->mh50Bmp );
346 		pSalData->mh50Bmp = 0;
347 	}
348 
349 	ImplClearHDCCache( pSalData );
350 	delete[] pSalData->mpHDCCache;
351 
352 	// Ditherpalette loeschen, wenn vorhanden
353 	if ( pSalData->mhDitherPal )
354 	{
355 		DeleteObject( pSalData->mhDitherPal );
356 		pSalData->mhDitherPal = 0;
357 	}
358 
359 	// delete buffers for dithering DIB patterns, if neccessary
360 	if ( pSalData->mhDitherDIB )
361 	{
362 		GlobalUnlock( pSalData->mhDitherDIB );
363 		GlobalFree( pSalData->mhDitherDIB );
364 		pSalData->mhDitherDIB = 0;
365 		delete[] pSalData->mpDitherDiff;
366 		delete[] pSalData->mpDitherLow;
367 		delete[] pSalData->mpDitherHigh;
368 	}
369 
370 	// delete SysColorList
371 	SysColorEntry* pEntry = pFirstSysColor;
372 	while( pEntry )
373 	{
374 		SysColorEntry* pTmp = pEntry->pNext;
375 		delete pEntry;
376 		pEntry = pTmp;
377 	}
378 	pFirstSysColor = NULL;
379 
380     // delete icon cache
381     SalIcon* pIcon = pSalData->mpFirstIcon;
382     pSalData->mpFirstIcon = NULL;
383     while( pIcon )
384     {
385         SalIcon* pTmp = pIcon->pNext;
386         DestroyIcon( pIcon->hIcon );
387         DestroyIcon( pIcon->hSmallIcon );
388         delete pIcon;
389         pIcon = pTmp;
390     }
391 
392     // delete temporary font list
393     ImplReleaseTempFonts( *pSalData );
394 }
395 
396 // -----------------------------------------------------------------------
397 
398 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
399 {
400 	// dither color?
401 	if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
402 		return TRUE;
403 
404 	PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
405 
406 	// standard palette color?
407 	for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
408 	{
409 		if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
410 			return TRUE;
411 	}
412 
413 	// extra color?
414 	if ( aImplExtraColor1.peRed == nRed &&
415 		 aImplExtraColor1.peGreen == nGreen &&
416 		 aImplExtraColor1.peBlue == nBlue )
417 	{
418 		return TRUE;
419 	}
420 
421 	return FALSE;
422 }
423 
424 // =======================================================================
425 
426 int ImplIsSysColorEntry( SalColor nSalColor )
427 {
428 	SysColorEntry*	pEntry = pFirstSysColor;
429 	const DWORD 	nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
430 										   SALCOLOR_GREEN( nSalColor ),
431 										   SALCOLOR_BLUE( nSalColor ) );
432 
433 	while ( pEntry )
434 	{
435 		if ( pEntry->nRGB == nTestRGB )
436 			return TRUE;
437 		pEntry = pEntry->pNext;
438 	}
439 
440 	return FALSE;
441 }
442 
443 // =======================================================================
444 
445 static void ImplInsertSysColorEntry( int nSysIndex )
446 {
447 	const DWORD nRGB = GetSysColor( nSysIndex );
448 
449 	if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
450 	{
451 		if ( !pFirstSysColor )
452 		{
453 			pActSysColor = pFirstSysColor = new SysColorEntry;
454 			pFirstSysColor->nRGB = nRGB;
455 			pFirstSysColor->pNext = NULL;
456 		}
457 		else
458 		{
459 			pActSysColor = pActSysColor->pNext = new SysColorEntry;
460 			pActSysColor->nRGB = nRGB;
461 			pActSysColor->pNext = NULL;
462 		}
463 	}
464 }
465 
466 // =======================================================================
467 
468 void ImplUpdateSysColorEntries()
469 {
470 	// delete old SysColorList
471 	SysColorEntry* pEntry = pFirstSysColor;
472 	while( pEntry )
473 	{
474 		SysColorEntry* pTmp = pEntry->pNext;
475 		delete pEntry;
476 		pEntry = pTmp;
477 	}
478 	pActSysColor = pFirstSysColor = NULL;
479 
480 	// create new sys color list
481 	ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
482 	ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
483 	if( aSalShlData.mnVersion >= 410 )
484 	{
485 		ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
486 		ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
487 	}
488 	ImplInsertSysColorEntry( COLOR_3DFACE );
489 	ImplInsertSysColorEntry( COLOR_3DHILIGHT );
490 	ImplInsertSysColorEntry( COLOR_3DLIGHT );
491 	ImplInsertSysColorEntry( COLOR_3DSHADOW );
492 	ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
493 	ImplInsertSysColorEntry( COLOR_INFOBK );
494 	ImplInsertSysColorEntry( COLOR_INFOTEXT );
495 	ImplInsertSysColorEntry( COLOR_BTNTEXT );
496 	ImplInsertSysColorEntry( COLOR_WINDOW );
497 	ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
498 	ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
499 	ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
500 	ImplInsertSysColorEntry( COLOR_MENU );
501 	ImplInsertSysColorEntry( COLOR_MENUTEXT );
502 	ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
503 	ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
504 	ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
505 	ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
506 }
507 
508 // -----------------------------------------------------------------------
509 
510 static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
511 {
512 	SalColor nSalColor;
513 	if ( nROPColor == SAL_ROP_0 )
514 		nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
515 	else
516 		nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
517 	return nSalColor;
518 }
519 
520 // =======================================================================
521 
522 void ImplSalInitGraphics( WinSalGraphics* pData )
523 {
524 	// Beim Printer berechnen wir die minimale Linienstaerke
525 	if ( pData->mbPrinter )
526 	{
527 		int nDPIX = GetDeviceCaps( pData->getHDC(), LOGPIXELSX );
528 		if ( nDPIX <= 300 )
529 			pData->mnPenWidth = 0;
530 		else
531 			pData->mnPenWidth = nDPIX/300;
532 	}
533 
534 	::SetTextAlign( pData->getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
535 	::SetBkMode( pData->getHDC(), TRANSPARENT );
536 	::SetROP2( pData->getHDC(), R2_COPYPEN );
537 }
538 
539 // -----------------------------------------------------------------------
540 
541 void ImplSalDeInitGraphics( WinSalGraphics* pData )
542 {
543     // clear clip region
544 	SelectClipRgn( pData->getHDC(), 0 );
545 	// select default objects
546 	if ( pData->mhDefPen )
547 		SelectPen( pData->getHDC(), pData->mhDefPen );
548 	if ( pData->mhDefBrush )
549 		SelectBrush( pData->getHDC(), pData->mhDefBrush );
550 	if ( pData->mhDefFont )
551 		SelectFont( pData->getHDC(), pData->mhDefFont );
552 }
553 
554 // =======================================================================
555 
556 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
557 {
558 	SalData*	pSalData = GetSalData();
559 	HDCCache*	pC = &pSalData->mpHDCCache[ nID ];
560 
561 	if( !pC->mhDC )
562 	{
563 		HDC hDC = GetDC( 0 );
564 
565 		// neuen DC mit DefaultBitmap anlegen
566 		pC->mhDC = CreateCompatibleDC( hDC );
567 
568 		if( pSalData->mhDitherPal )
569 		{
570 			pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
571 			RealizePalette( pC->mhDC );
572 		}
573 
574 		pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
575 		pC->mhDefBmp = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
576 
577 		ReleaseDC( 0, hDC );
578 	}
579 
580 	if ( hBmp )
581 		SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
582 	else
583 		pC->mhActBmp = 0;
584 
585 	return pC->mhDC;
586 }
587 
588 // =======================================================================
589 
590 void ImplReleaseCachedDC( sal_uLong nID )
591 {
592 	SalData*	pSalData = GetSalData();
593 	HDCCache*	pC = &pSalData->mpHDCCache[ nID ];
594 
595 	if ( pC->mhActBmp )
596 		SelectObject( pC->mhDC, pC->mhSelBmp );
597 }
598 
599 // =======================================================================
600 
601 void ImplClearHDCCache( SalData* pData )
602 {
603 	for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
604 	{
605 		HDCCache* pC = &pData->mpHDCCache[ i ];
606 
607 		if( pC->mhDC )
608 		{
609 			SelectObject( pC->mhDC, pC->mhDefBmp );
610 
611 			if( pC->mhDefPal )
612 				SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
613 
614 			DeleteDC( pC->mhDC );
615 			DeleteObject( pC->mhSelBmp );
616 		}
617 	}
618 }
619 
620 // =======================================================================
621 
622 // #100127# Fill point and flag memory from array of points which
623 // might also contain bezier control points for the PolyDraw() GDI method
624 // Make sure pWinPointAry and pWinFlagAry are big enough
625 void ImplPreparePolyDraw( bool						bCloseFigures,
626                           sal_uLong 					nPoly,
627                           const sal_uLong* 				pPoints,
628                           const SalPoint* const* 	pPtAry,
629                           const BYTE* const* 		pFlgAry,
630                           POINT* 					pWinPointAry,
631                           BYTE* 					pWinFlagAry		)
632 {
633     sal_uLong nCurrPoly;
634     for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly )
635     {
636         const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ );
637         const BYTE* pCurrFlag = *pFlgAry++;
638         const sal_uLong nCurrPoints = *pPoints++;
639         const bool bHaveFlagArray( pCurrFlag );
640         sal_uLong nCurrPoint;
641 
642         if( nCurrPoints )
643         {
644             // start figure
645             *pWinPointAry++ = *pCurrPoint++;
646             *pWinFlagAry++  = PT_MOVETO;
647             ++pCurrFlag;
648 
649             for( nCurrPoint=1; nCurrPoint<nCurrPoints; )
650             {
651                 // #102067# Check existence of flag array
652                 if( bHaveFlagArray &&
653                     ( nCurrPoint + 2 ) < nCurrPoints )
654                 {
655                     BYTE P4( pCurrFlag[ 2 ] );
656 
657                     if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) &&
658                         ( POLY_CONTROL == pCurrFlag[ 1 ] ) &&
659                         ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
660                     {
661                         // control point one
662                         *pWinPointAry++ = *pCurrPoint++;
663                         *pWinFlagAry++  = PT_BEZIERTO;
664 
665                         // control point two
666                         *pWinPointAry++ = *pCurrPoint++;
667                         *pWinFlagAry++  = PT_BEZIERTO;
668 
669                         // end point
670                         *pWinPointAry++ = *pCurrPoint++;
671                         *pWinFlagAry++  = PT_BEZIERTO;
672 
673                         nCurrPoint += 3;
674                         pCurrFlag += 3;
675                         continue;
676                     }
677                 }
678 
679                 // regular line point
680                 *pWinPointAry++ = *pCurrPoint++;
681                 *pWinFlagAry++  = PT_LINETO;
682                 ++pCurrFlag;
683                 ++nCurrPoint;
684             }
685 
686             // end figure?
687             if( bCloseFigures )
688                 pWinFlagAry[-1] |= PT_CLOSEFIGURE;
689         }
690     }
691 }
692 
693 // =======================================================================
694 
695 // #100127# draw an array of points which might also contain bezier control points
696 void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
697 {
698     if( nPoints )
699     {
700         sal_uInt16 i;
701         // TODO: profile whether the following options are faster:
702         // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
703         // b) convert our flag array to window's and use PolyDraw
704 
705         MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL );
706         ++pPtAry; ++pFlgAry;
707 
708         for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry )
709         {
710             if( *pFlgAry != POLY_CONTROL )
711             {
712                 LineTo( hdc, pPtAry->mnX, pPtAry->mnY );
713             }
714             else if( nPoints - i > 2 )
715             {
716                 PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 );
717                 i += 2; pPtAry += 2; pFlgAry += 2;
718             }
719         }
720     }
721 }
722 
723 // =======================================================================
724 
725 WinSalGraphics::WinSalGraphics()
726 {
727     for( int i = 0; i < MAX_FALLBACK; ++i )
728     {
729         mhFonts[ i ] = 0;
730         mpWinFontData[ i ]  = NULL;
731         mpWinFontEntry[ i ] = NULL;
732     }
733 
734     mfFontScale = 1.0;
735 
736 	mhLocalDC			= 0;
737 	mhPen				= 0;
738 	mhBrush				= 0;
739 	mhRegion 			= 0;
740 	mhDefPen 			= 0;
741 	mhDefBrush			= 0;
742 	mhDefFont			= 0;
743 	mhDefPal 			= 0;
744 	mpStdClipRgnData 	= NULL;
745 	mpLogFont			= NULL;
746 	mpFontCharSets		= NULL;
747 	mpFontAttrCache		= NULL;
748 	mnFontCharSetCount	= 0;
749 	mpFontKernPairs		= NULL;
750 	mnFontKernPairCount	= 0;
751 	mbFontKernInit		= FALSE;
752 	mbXORMode			= FALSE;
753 	mnPenWidth			= GSL_PEN_WIDTH;
754 }
755 
756 // -----------------------------------------------------------------------
757 
758 WinSalGraphics::~WinSalGraphics()
759 {
760 	// free obsolete GDI objekts
761         ReleaseFonts();
762 
763 	if ( mhPen )
764 	{
765 		if ( !mbStockPen )
766 			DeletePen( mhPen );
767 	}
768 	if ( mhBrush )
769 	{
770 		if ( !mbStockBrush )
771 			DeleteBrush( mhBrush );
772 	}
773 
774 	if ( mhRegion )
775 	{
776 		DeleteRegion( mhRegion );
777 		mhRegion = 0;
778 	}
779 
780 	// Cache-Daten zerstoeren
781 	if ( mpStdClipRgnData )
782 		delete [] mpStdClipRgnData;
783 
784 	if ( mpLogFont )
785 		delete mpLogFont;
786 
787 	if ( mpFontCharSets )
788 		delete mpFontCharSets;
789 
790 	if ( mpFontKernPairs )
791 		delete mpFontKernPairs;
792 }
793 
794 // -----------------------------------------------------------------------
795 
796 void WinSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
797 {
798 	rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
799 	rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
800 
801     // #111139# this fixes the symptom of div by zero on startup
802     // however, printing will fail most likely as communication with
803     // the printer seems not to work in this case
804     if( !rDPIX || !rDPIY )
805         rDPIX = rDPIY = 600;
806 }
807 
808 // -----------------------------------------------------------------------
809 
810 sal_uInt16 WinSalGraphics::GetBitCount()
811 {
812 	return (sal_uInt16)GetDeviceCaps( getHDC(), BITSPIXEL );
813 }
814 
815 // -----------------------------------------------------------------------
816 
817 long WinSalGraphics::GetGraphicsWidth() const
818 {
819     if( mhWnd && IsWindow( mhWnd ) )
820     {
821         WinSalFrame* pFrame = GetWindowPtr( mhWnd );
822         if( pFrame )
823         {
824             if( pFrame->maGeometry.nWidth )
825                 return pFrame->maGeometry.nWidth;
826             else
827             {
828                 // TODO: perhaps not needed, maGeometry should always be up-to-date
829                 RECT aRect;
830                 GetClientRect( mhWnd, &aRect );
831                 return aRect.right;
832             }
833         }
834     }
835 
836     return 0;
837 }
838 
839 // -----------------------------------------------------------------------
840 
841 void WinSalGraphics::ResetClipRegion()
842 {
843 	if ( mhRegion )
844 	{
845 		DeleteRegion( mhRegion );
846 		mhRegion = 0;
847 	}
848 
849 	SelectClipRgn( getHDC(), 0 );
850 }
851 
852 // -----------------------------------------------------------------------
853 
854 bool WinSalGraphics::setClipRegion( const Region& i_rClip )
855 {
856 	if ( mhRegion )
857 	{
858 		DeleteRegion( mhRegion );
859 		mhRegion = 0;
860 	}
861 
862 	if( i_rClip.HasPolyPolygonOrB2DPolyPolygon() )
863 	{
864 	    const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() );
865         const sal_uInt32 nCount(aPolyPolygon.count());
866 
867         if( nCount )
868         {
869             std::vector< POINT > aPolyPoints;
870             aPolyPoints.reserve( 1024 );
871             std::vector< INT > aPolyCounts( nCount, 0 );
872 
873             for(sal_uInt32 a(0); a < nCount; a++)
874             {
875                 basegfx::B2DPolygon aPoly(aPolyPolygon.getB2DPolygon(a));
876 
877                 aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 );
878                 const sal_uInt32 nPoints = aPoly.count();
879                 aPolyCounts[a] = nPoints;
880 
881                 for( sal_uInt32 b = 0; b < nPoints; b++ )
882                 {
883                     basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) );
884                     POINT aPOINT;
885                     aPOINT.x = (LONG)aPt.getX();
886                     aPOINT.y = (LONG)aPt.getY();
887                     aPolyPoints.push_back( aPOINT );
888                 }
889             }
890 
891             mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE );
892         }
893 	}
894 	else
895 	{
896         RectangleVector aRectangles;
897         i_rClip.GetRegionRectangles(aRectangles);
898 
899         //ULONG nRectCount = i_rClip.GetRectCount();
900 	    ULONG nRectBufSize = sizeof(RECT)*aRectangles.size();
901         if ( aRectangles.size() < SAL_CLIPRECT_COUNT )
902         {
903             if ( !mpStdClipRgnData )
904                 mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
905             mpClipRgnData = mpStdClipRgnData;
906         }
907         else
908             mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
909         mpClipRgnData->rdh.dwSize	= sizeof( RGNDATAHEADER );
910         mpClipRgnData->rdh.iType 	= RDH_RECTANGLES;
911         mpClipRgnData->rdh.nCount	= aRectangles.size();
912         mpClipRgnData->rdh.nRgnSize	= nRectBufSize;
913         RECT*		pBoundRect = &(mpClipRgnData->rdh.rcBound);
914         SetRectEmpty( pBoundRect );
915         RECT* pNextClipRect         = (RECT*)(&(mpClipRgnData->Buffer));
916         bool bFirstClipRect         = true;
917 
918         for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
919         {
920             const long nW(aRectIter->GetWidth());
921             const long nH(aRectIter->GetHeight());
922 
923             if(nW && nH)
924             {
925                 const long nRight(aRectIter->Left() + nW);
926                 const long nBottom(aRectIter->Top() + nH);
927 
928                 if(bFirstClipRect)
929                 {
930                     pBoundRect->left = aRectIter->Left();
931                     pBoundRect->top = aRectIter->Top();
932                     pBoundRect->right = nRight;
933                     pBoundRect->bottom = nBottom;
934                     bFirstClipRect = false;
935                 }
936                 else
937                 {
938                     if(aRectIter->Left() < pBoundRect->left)
939                     {
940                         pBoundRect->left = (int)aRectIter->Left();
941                     }
942 
943                     if(aRectIter->Top() < pBoundRect->top)
944                     {
945                         pBoundRect->top = (int)aRectIter->Top();
946                     }
947 
948                     if(nRight > pBoundRect->right)
949                     {
950                         pBoundRect->right = (int)nRight;
951                     }
952 
953                     if(nBottom > pBoundRect->bottom)
954                     {
955                         pBoundRect->bottom = (int)nBottom;
956                     }
957                 }
958 
959                 pNextClipRect->left = (int)aRectIter->Left();
960                 pNextClipRect->top = (int)aRectIter->Top();
961                 pNextClipRect->right = (int)nRight;
962                 pNextClipRect->bottom = (int)nBottom;
963                 pNextClipRect++;
964             }
965             else
966             {
967                 mpClipRgnData->rdh.nCount--;
968                 mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
969             }
970         }
971 
972         //ImplRegionInfo aInfo;
973         //long nX, nY, nW, nH;
974         //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
975         //while( bRegionRect )
976         //{
977         //    if ( nW && nH )
978         //    {
979         //        long		nRight = nX + nW;
980         //        long		nBottom = nY + nH;
981         //
982         //        if ( bFirstClipRect )
983         //        {
984         //            pBoundRect->left	= nX;
985         //            pBoundRect->top 	= nY;
986         //            pBoundRect->right	= nRight;
987         //            pBoundRect->bottom	= nBottom;
988         //            bFirstClipRect = false;
989         //        }
990         //        else
991         //        {
992         //            if ( nX < pBoundRect->left )
993         //                pBoundRect->left = (int)nX;
994         //
995         //            if ( nY < pBoundRect->top )
996         //                pBoundRect->top = (int)nY;
997         //
998         //            if ( nRight > pBoundRect->right )
999         //                pBoundRect->right = (int)nRight;
1000         //
1001         //            if ( nBottom > pBoundRect->bottom )
1002         //                pBoundRect->bottom = (int)nBottom;
1003         //        }
1004         //
1005         //        pNextClipRect->left 	= (int)nX;
1006         //        pNextClipRect->top		= (int)nY;
1007         //        pNextClipRect->right	= (int)nRight;
1008         //        pNextClipRect->bottom	= (int)nBottom;
1009         //        pNextClipRect++;
1010         //    }
1011         //    else
1012         //    {
1013         //        mpClipRgnData->rdh.nCount--;
1014         //        mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
1015         //    }
1016         //    bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
1017         //}
1018 
1019         // create clip region from ClipRgnData
1020         if ( mpClipRgnData->rdh.nCount == 1 )
1021         {
1022             RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1023             mhRegion = CreateRectRgn( pRect->left, pRect->top,
1024                                                      pRect->right, pRect->bottom );
1025         }
1026         else if( mpClipRgnData->rdh.nCount > 1 )
1027         {
1028             ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
1029             mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
1030 
1031             // if ExtCreateRegion(...) is not supported
1032             if( !mhRegion )
1033             {
1034                 RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData;
1035 
1036                 if( pHeader->nCount )
1037                 {
1038                     RECT* pRect = (RECT*) mpClipRgnData->Buffer;
1039                     mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
1040                     pRect++;
1041 
1042                     for( ULONG n = 1; n < pHeader->nCount; n++, pRect++ )
1043                     {
1044                         HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
1045                         CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR );
1046                         DeleteRegion( hRgn );
1047                     }
1048                 }
1049             }
1050 
1051             if ( mpClipRgnData != mpStdClipRgnData )
1052                 delete [] mpClipRgnData;
1053         }
1054 	}
1055 
1056 	if( mhRegion )
1057 	    SelectClipRgn( getHDC(), mhRegion );
1058 	return mhRegion != 0;
1059 }
1060 
1061 // -----------------------------------------------------------------------
1062 
1063 void WinSalGraphics::SetLineColor()
1064 {
1065 	// create and select new pen
1066 	HPEN hNewPen = GetStockPen( NULL_PEN );
1067 	HPEN hOldPen = SelectPen( getHDC(), hNewPen );
1068 
1069 	// destory or save old pen
1070 	if ( mhPen )
1071 	{
1072 		if ( !mbStockPen )
1073 			DeletePen( mhPen );
1074 	}
1075 	else
1076 		mhDefPen = hOldPen;
1077 
1078 	// set new data
1079 	mhPen		= hNewPen;
1080 	mbPen		= FALSE;
1081 	mbStockPen	= TRUE;
1082 }
1083 
1084 // -----------------------------------------------------------------------
1085 
1086 void WinSalGraphics::SetLineColor( SalColor nSalColor )
1087 {
1088     maLineColor = nSalColor;
1089 	COLORREF	nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
1090 										SALCOLOR_GREEN( nSalColor ),
1091 										SALCOLOR_BLUE( nSalColor ) );
1092 	HPEN		hNewPen = 0;
1093 	sal_Bool		bStockPen = FALSE;
1094 
1095 	// search for stock pen (only screen, because printer have problems,
1096 	// when we use stock objects)
1097 	if ( !mbPrinter )
1098 	{
1099 		SalData* pSalData = GetSalData();
1100 		for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ )
1101 		{
1102 			if ( nPenColor == pSalData->maStockPenColorAry[i] )
1103 			{
1104 				hNewPen = pSalData->mhStockPenAry[i];
1105 				bStockPen = TRUE;
1106 				break;
1107 			}
1108 		}
1109 	}
1110 
1111 	// create new pen
1112 	if ( !hNewPen )
1113 	{
1114 		if ( !mbPrinter )
1115 		{
1116 			if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
1117 				nPenColor = PALRGB_TO_RGB( nPenColor );
1118 		}
1119 
1120 		hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor );
1121 		bStockPen = FALSE;
1122 	}
1123 
1124 	// select new pen
1125 	HPEN hOldPen = SelectPen( getHDC(), hNewPen );
1126 
1127 	// destory or save old pen
1128 	if ( mhPen )
1129 	{
1130 		if ( !mbStockPen )
1131 			DeletePen( mhPen );
1132 	}
1133 	else
1134 		mhDefPen = hOldPen;
1135 
1136 	// set new data
1137 	mnPenColor	= nPenColor;
1138 	mhPen		= hNewPen;
1139 	mbPen		= TRUE;
1140 	mbStockPen	= bStockPen;
1141 }
1142 
1143 // -----------------------------------------------------------------------
1144 
1145 void WinSalGraphics::SetFillColor()
1146 {
1147 	// create and select new brush
1148 	HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
1149 	HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush );
1150 
1151 	// destory or save old brush
1152 	if ( mhBrush )
1153 	{
1154 		if ( !mbStockBrush )
1155 			DeleteBrush( mhBrush );
1156 	}
1157 	else
1158 		mhDefBrush = hOldBrush;
1159 
1160 	// set new data
1161 	mhBrush		= hNewBrush;
1162 	mbBrush		= FALSE;
1163 	mbStockBrush = TRUE;
1164 }
1165 
1166 // -----------------------------------------------------------------------
1167 
1168 void WinSalGraphics::SetFillColor( SalColor nSalColor )
1169 {
1170     maFillColor = nSalColor;
1171 	SalData*	pSalData	= GetSalData();
1172 	BYTE		nRed		= SALCOLOR_RED( nSalColor );
1173 	BYTE		nGreen		= SALCOLOR_GREEN( nSalColor );
1174 	BYTE		nBlue		= SALCOLOR_BLUE( nSalColor );
1175 	COLORREF	nBrushColor = PALETTERGB( nRed, nGreen, nBlue );
1176 	HBRUSH		hNewBrush	= 0;
1177 	sal_Bool		bStockBrush = FALSE;
1178 
1179 	// search for stock brush (only screen, because printer have problems,
1180 	// when we use stock objects)
1181 	if ( !mbPrinter )
1182 	{
1183 		for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ )
1184 		{
1185 			if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] )
1186 			{
1187 				hNewBrush = pSalData->mhStockBrushAry[i];
1188 				bStockBrush = TRUE;
1189 				break;
1190 			}
1191 		}
1192 	}
1193 
1194 	// create new brush
1195 	if ( !hNewBrush )
1196 	{
1197 		if ( mbPrinter || !pSalData->mhDitherDIB )
1198 			hNewBrush = CreateSolidBrush( nBrushColor );
1199 		else
1200 		{
1201 			if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount )
1202 			{
1203 				BYTE* pTmp = pSalData->mpDitherDIBData;
1204 				long* pDitherDiff = pSalData->mpDitherDiff;
1205 				BYTE* pDitherLow = pSalData->mpDitherLow;
1206 				BYTE* pDitherHigh = pSalData->mpDitherHigh;
1207 
1208 				for( long nY = 0L; nY < 8L; nY++ )
1209 				{
1210 					for( long nX = 0L; nX < 8L; nX++ )
1211 					{
1212 						const long nThres = aOrdDither16Bit[ nY ][ nX ];
1213 						*pTmp++ = DMAP( nBlue, nThres );
1214 						*pTmp++ = DMAP( nGreen, nThres );
1215 						*pTmp++ = DMAP( nRed, nThres );
1216 					}
1217 				}
1218 
1219 				hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS );
1220 			}
1221 			else if ( ImplIsSysColorEntry( nSalColor ) )
1222 			{
1223 				nBrushColor = PALRGB_TO_RGB( nBrushColor );
1224 				hNewBrush = CreateSolidBrush( nBrushColor );
1225 			}
1226 			else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) )
1227 				hNewBrush = CreateSolidBrush( nBrushColor );
1228 			else
1229 			{
1230 				BYTE* pTmp = pSalData->mpDitherDIBData;
1231 				long* pDitherDiff = pSalData->mpDitherDiff;
1232 				BYTE* pDitherLow = pSalData->mpDitherLow;
1233 				BYTE* pDitherHigh = pSalData->mpDitherHigh;
1234 
1235 				for ( long nY = 0L; nY < 8L; nY++ )
1236 				{
1237 					for ( long nX = 0L; nX < 8L; nX++ )
1238 					{
1239 						const long nThres = aOrdDither8Bit[ nY ][ nX ];
1240 						*pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36;
1241 						pTmp++;
1242 					}
1243 				}
1244 
1245 				hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
1246 			}
1247 		}
1248 
1249 		bStockBrush = FALSE;
1250 	}
1251 
1252 	// select new brush
1253 	HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush );
1254 
1255 	// destory or save old brush
1256 	if ( mhBrush )
1257 	{
1258 		if ( !mbStockBrush )
1259 			DeleteBrush( mhBrush );
1260 	}
1261 	else
1262 		mhDefBrush = hOldBrush;
1263 
1264 	// set new data
1265 	mnBrushColor = nBrushColor;
1266 	mhBrush		= hNewBrush;
1267 	mbBrush		= TRUE;
1268 	mbStockBrush = bStockBrush;
1269 }
1270 
1271 // -----------------------------------------------------------------------
1272 
1273 void WinSalGraphics::SetXORMode( bool bSet, bool )
1274 {
1275 	mbXORMode = bSet;
1276 	::SetROP2( getHDC(), bSet ? R2_XORPEN : R2_COPYPEN );
1277 }
1278 
1279 // -----------------------------------------------------------------------
1280 
1281 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
1282 {
1283 	SetLineColor( ImplGetROPSalColor( nROPColor ) );
1284 }
1285 
1286 // -----------------------------------------------------------------------
1287 
1288 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
1289 {
1290 	SetFillColor( ImplGetROPSalColor( nROPColor ) );
1291 }
1292 
1293 // -----------------------------------------------------------------------
1294 
1295 void WinSalGraphics::drawPixel( long nX, long nY )
1296 {
1297 	if ( mbXORMode )
1298 	{
1299 		HBRUSH	hBrush = CreateSolidBrush( mnPenColor );
1300 		HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1301 		PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1302 		SelectBrush( getHDC(), hOldBrush );
1303 		DeleteBrush( hBrush );
1304 	}
1305 	else
1306 		SetPixel( getHDC(), (int)nX, (int)nY, mnPenColor );
1307 }
1308 
1309 // -----------------------------------------------------------------------
1310 
1311 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
1312 {
1313 	COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1314 								SALCOLOR_GREEN( nSalColor ),
1315 								SALCOLOR_BLUE( nSalColor ) );
1316 
1317 	if ( !mbPrinter &&
1318 		 GetSalData()->mhDitherPal &&
1319 		 ImplIsSysColorEntry( nSalColor ) )
1320 		nCol = PALRGB_TO_RGB( nCol );
1321 
1322 	if ( mbXORMode )
1323 	{
1324 		HBRUSH	hBrush = CreateSolidBrush( nCol );
1325 		HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1326 		PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1327 		SelectBrush( getHDC(), hOldBrush );
1328 		DeleteBrush( hBrush );
1329 	}
1330 	else
1331 		::SetPixel( getHDC(), (int)nX, (int)nY, nCol );
1332 }
1333 
1334 // -----------------------------------------------------------------------
1335 
1336 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
1337 {
1338 	MoveToEx( getHDC(), (int)nX1, (int)nY1, NULL );
1339 
1340 	// we must paint the endpoint
1341 	int bPaintEnd = TRUE;
1342 	if ( nX1 == nX2 )
1343 	{
1344 		bPaintEnd = FALSE;
1345 		if ( nY1 <= nY2 )
1346 			nY2++;
1347 		else
1348 			nY2--;
1349 	}
1350 	if ( nY1 == nY2 )
1351 	{
1352 		bPaintEnd = FALSE;
1353 		if ( nX1 <= nX2 )
1354 			nX2++;
1355 		else
1356 			nX2--;
1357 	}
1358 
1359 	LineTo( getHDC(), (int)nX2, (int)nY2 );
1360 
1361 	if ( bPaintEnd && !mbPrinter )
1362 	{
1363 		if ( mbXORMode )
1364 		{
1365 			HBRUSH	hBrush = CreateSolidBrush( mnPenColor );
1366 			HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1367 			PatBlt( getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
1368 			SelectBrush( getHDC(), hOldBrush );
1369 			DeleteBrush( hBrush );
1370 		}
1371 		else
1372 			SetPixel( getHDC(), (int)nX2, (int)nY2, mnPenColor );
1373 	}
1374 }
1375 
1376 // -----------------------------------------------------------------------
1377 
1378 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
1379 {
1380 	if ( !mbPen )
1381 	{
1382 		if ( !mbPrinter )
1383 		{
1384 			PatBlt( getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight,
1385 					mbXORMode ? PATINVERT : PATCOPY );
1386 		}
1387 		else
1388 		{
1389 			RECT aWinRect;
1390 			aWinRect.left	= nX;
1391 			aWinRect.top	= nY;
1392 			aWinRect.right	= nX+nWidth;
1393 			aWinRect.bottom = nY+nHeight;
1394 			::FillRect( getHDC(), &aWinRect, mhBrush );
1395 		}
1396 	}
1397 	else
1398 		WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
1399 }
1400 
1401 // -----------------------------------------------------------------------
1402 
1403 void WinSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry )
1404 {
1405 	// Unter NT koennen wir das Array direkt weiterreichen
1406 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1407 				"WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
1408 
1409 	POINT* pWinPtAry = (POINT*)pPtAry;
1410 	// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1411 	// von Punkten
1412 	if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1413 		Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
1414 }
1415 
1416 // -----------------------------------------------------------------------
1417 
1418 void WinSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
1419 {
1420 	// Unter NT koennen wir das Array direkt weiterreichen
1421 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1422 				"WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
1423 
1424 	POINT* pWinPtAry = (POINT*)pPtAry;
1425 	// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1426 	// von Punkten
1427 	if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1428 		WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
1429 }
1430 
1431 // -----------------------------------------------------------------------
1432 
1433 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1434 								   PCONSTSALPOINT* pPtAry )
1435 {
1436 	UINT	aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF];
1437 	UINT*	pWinPointAry;
1438 	UINT	nPolyPolyPoints = 0;
1439 	UINT	nPoints;
1440 	UINT	i;
1441 
1442 	if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
1443 		pWinPointAry = aWinPointAry;
1444 	else
1445 		pWinPointAry = new UINT[nPoly];
1446 
1447 	for ( i = 0; i < (UINT)nPoly; i++ )
1448 	{
1449 		nPoints = (UINT)pPoints[i]+1;
1450 		pWinPointAry[i] = nPoints;
1451 		nPolyPolyPoints += nPoints;
1452 	}
1453 
1454 	POINT  aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF];
1455 	POINT* pWinPointAryAry;
1456 	if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF )
1457 		pWinPointAryAry = aWinPointAryAry;
1458 	else
1459 		pWinPointAryAry = new POINT[nPolyPolyPoints];
1460 	// Unter NT koennen wir das Array direkt weiterreichen
1461 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1462 				"WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" );
1463 	const SalPoint* pPolyAry;
1464 	UINT			n = 0;
1465 	for ( i = 0; i < (UINT)nPoly; i++ )
1466 	{
1467 		nPoints = pWinPointAry[i];
1468 		pPolyAry = pPtAry[i];
1469 		memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) );
1470 		pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n];
1471 		n += nPoints;
1472 	}
1473 
1474 	if ( !WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
1475 		 (nPolyPolyPoints > MAX_64KSALPOINTS) )
1476 	{
1477 		nPolyPolyPoints  = 0;
1478 		nPoly = 0;
1479 		do
1480 		{
1481 			nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
1482 			nPoly++;
1483 		}
1484 		while ( nPolyPolyPoints < MAX_64KSALPOINTS );
1485 		nPoly--;
1486 		if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
1487 			pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
1488 		if ( nPoly == 1 )
1489 			WIN_Polygon( getHDC(), pWinPointAryAry, *pWinPointAry );
1490 		else
1491 			WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly );
1492 	}
1493 
1494 	if ( pWinPointAry != aWinPointAry )
1495 		delete [] pWinPointAry;
1496 	if ( pWinPointAryAry != aWinPointAryAry )
1497 		delete [] pWinPointAryAry;
1498 }
1499 
1500 // -----------------------------------------------------------------------
1501 
1502 #define SAL_POLY_STACKBUF		32
1503 
1504 // -----------------------------------------------------------------------
1505 
1506 sal_Bool WinSalGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1507 {
1508 #ifdef USE_GDI_BEZIERS
1509 	// Unter NT koennen wir das Array direkt weiterreichen
1510 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1511 				"WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
1512 
1513     ImplRenderPath( getHDC(), nPoints, pPtAry, pFlgAry );
1514 
1515     return sal_True;
1516 #else
1517     return sal_False;
1518 #endif
1519 }
1520 
1521 // -----------------------------------------------------------------------
1522 
1523 sal_Bool WinSalGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1524 {
1525 #ifdef USE_GDI_BEZIERS
1526 	// Unter NT koennen wir das Array direkt weiterreichen
1527 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1528 				"WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" );
1529 
1530     POINT	aStackAry1[SAL_POLY_STACKBUF];
1531     BYTE	aStackAry2[SAL_POLY_STACKBUF];
1532     POINT* 	pWinPointAry;
1533     BYTE* 	pWinFlagAry;
1534     if( nPoints > SAL_POLY_STACKBUF )
1535     {
1536         pWinPointAry = new POINT[ nPoints ];
1537         pWinFlagAry = new BYTE[ nPoints ];
1538     }
1539     else
1540     {
1541         pWinPointAry = aStackAry1;
1542         pWinFlagAry = aStackAry2;
1543     }
1544 
1545     ImplPreparePolyDraw(true, 1, &nPoints, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
1546 
1547     sal_Bool bRet( sal_False );
1548 
1549     if( BeginPath( getHDC() ) )
1550     {
1551         PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nPoints);
1552 
1553         if( EndPath( getHDC() ) )
1554         {
1555             if( StrokeAndFillPath( getHDC() ) )
1556                 bRet = sal_True;
1557         }
1558     }
1559 
1560     if( pWinPointAry != aStackAry1 )
1561     {
1562         delete [] pWinPointAry;
1563         delete [] pWinFlagAry;
1564     }
1565 
1566     return bRet;
1567 #else
1568     return sal_False;
1569 #endif
1570 }
1571 
1572 // -----------------------------------------------------------------------
1573 
1574 sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1575                                              const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
1576 {
1577 #ifdef USE_GDI_BEZIERS
1578 	// Unter NT koennen wir das Array direkt weiterreichen
1579 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1580 				"WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
1581 
1582     sal_uLong nCurrPoly, nTotalPoints;
1583     const sal_uLong* pCurrPoints = pPoints;
1584     for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
1585         nTotalPoints += *pCurrPoints++;
1586 
1587     POINT	aStackAry1[SAL_POLY_STACKBUF];
1588     BYTE	aStackAry2[SAL_POLY_STACKBUF];
1589     POINT* 	pWinPointAry;
1590     BYTE* 	pWinFlagAry;
1591     if( nTotalPoints > SAL_POLY_STACKBUF )
1592     {
1593         pWinPointAry = new POINT[ nTotalPoints ];
1594         pWinFlagAry = new BYTE[ nTotalPoints ];
1595     }
1596     else
1597     {
1598         pWinPointAry = aStackAry1;
1599         pWinFlagAry = aStackAry2;
1600     }
1601 
1602     ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
1603 
1604     sal_Bool bRet( sal_False );
1605 
1606     if( BeginPath( getHDC() ) )
1607     {
1608         PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints);
1609 
1610         if( EndPath( getHDC() ) )
1611         {
1612             if( StrokeAndFillPath( getHDC() ) )
1613                 bRet = sal_True;
1614         }
1615     }
1616 
1617     if( pWinPointAry != aStackAry1 )
1618     {
1619         delete [] pWinPointAry;
1620         delete [] pWinFlagAry;
1621     }
1622 
1623     return bRet;
1624 #else
1625     return sal_False;
1626 #endif
1627 }
1628 
1629 // -----------------------------------------------------------------------
1630 
1631 #define POSTSCRIPT_BUFSIZE 0x4000			// MAXIMUM BUFSIZE EQ 0xFFFF
1632 #define POSTSCRIPT_BOUNDINGSEARCH 0x1000	// we only try to get the BoundingBox
1633 											// in the first 4096 bytes
1634 
1635 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize )
1636 {
1637 	while ( nComp-- >= nSize )
1638 	{
1639 		sal_uLong i;
1640 		for ( i = 0; i < nSize; i++ )
1641 		{
1642 			if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
1643 				break;
1644 		}
1645 		if ( i == nSize )
1646 			return pSource;
1647 		pSource++;
1648 	}
1649 	return NULL;
1650 }
1651 
1652 static sal_Bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
1653 {
1654 	sal_Bool	bRetValue = FALSE;
1655 	BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
1656 	if ( pDest )
1657 	{
1658 		nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
1659 		pDest += 14;
1660 
1661 		int nSizeLeft = nSize - ( pDest - pSource );
1662 		if ( nSizeLeft > 100 )
1663 			nSizeLeft = 100;	// only 100 bytes following the bounding box will be checked
1664 
1665 		int i;
1666 		for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
1667 		{
1668 			int 	nDivision = 1;
1669 			sal_Bool	bDivision = FALSE;
1670 			sal_Bool	bNegative = FALSE;
1671 			sal_Bool	bValid = TRUE;
1672 
1673 			while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
1674 			BYTE nByte = *pDest;
1675 			while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
1676 			{
1677 				switch ( nByte )
1678 				{
1679 					case '.' :
1680 						if ( bDivision )
1681 							bValid = FALSE;
1682 						else
1683 							bDivision = TRUE;
1684 						break;
1685 					case '-' :
1686 						bNegative = TRUE;
1687 						break;
1688 					default :
1689 						if ( ( nByte < '0' ) || ( nByte > '9' ) )
1690 							nSizeLeft = 1; 	// error parsing the bounding box values
1691 						else if ( bValid )
1692 						{
1693 							if ( bDivision )
1694 								nDivision*=10;
1695 							nNumb[i] *= 10;
1696 							nNumb[i] += nByte - '0';
1697 						}
1698 						break;
1699 				}
1700 				nSizeLeft--;
1701 				nByte = *(++pDest);
1702 			}
1703 			if ( bNegative )
1704 				nNumb[i] = -nNumb[i];
1705 			if ( bDivision && ( nDivision != 1 ) )
1706 				nNumb[i] /= nDivision;
1707 		}
1708 		if ( i == 4 )
1709 			bRetValue = TRUE;
1710 	}
1711 	return bRetValue;
1712 }
1713 
1714 sal_Bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
1715 {
1716 	sal_Bool bRetValue = FALSE;
1717 
1718 	if ( mbPrinter )
1719 	{
1720 		int nEscape = POSTSCRIPT_PASSTHROUGH;
1721 
1722 		if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
1723 		{
1724 			double	nBoundingBox[4];
1725 
1726 			if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
1727 			{
1728                 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1729 
1730                 // reserve place for a sal_uInt16
1731                 aBuf.append( "aa" );
1732 
1733                 // #107797# Write out EPS encapsulation header
1734                 // ----------------------------------------------------------------------------------
1735 
1736                 // directly taken from the PLRM 3.0, p. 726. Note:
1737                 // this will definitely cause problems when
1738                 // recursively creating and embedding PostScript files
1739                 // in OOo, since we use statically-named variables
1740                 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1741                 // op_count_salWin). Currently, I have no idea on how to
1742                 // work around that, except from scanning and
1743                 // interpreting the EPS for unused identifiers.
1744 
1745                 // append the real text
1746                 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1747                              "/dict_count_salWin countdictstack def\n"
1748                              "/op_count_salWin count 1 sub def\n"
1749                              "userdict begin\n"
1750                              "/showpage {} def\n"
1751                              "0 setgray 0 setlinecap\n"
1752                              "1 setlinewidth 0 setlinejoin\n"
1753                              "10 setmiterlimit [] 0 setdash newpath\n"
1754                              "/languagelevel where\n"
1755                              "{\n"
1756                              "  pop languagelevel\n"
1757                              "  1 ne\n"
1758                              "  {\n"
1759                              "    false setstrokeadjust false setoverprint\n"
1760                              "  } if\n"
1761                              "} if\n\n" );
1762 
1763 
1764                 // #i10737# Apply clipping manually
1765                 // ----------------------------------------------------------------------------------
1766 
1767                 // Windows seems to ignore any clipping at the HDC,
1768                 // when followed by a POSTSCRIPT_PASSTHROUGH
1769 
1770                 // Check whether we've got a clipping, consisting of
1771                 // exactly one rect (other cases should be, but aren't
1772                 // handled currently)
1773 
1774                 // TODO: Handle more than one rectangle here (take
1775                 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1776                 // characters!)
1777                 if ( mhRegion != 0 &&
1778                      mpStdClipRgnData != NULL &&
1779                      mpClipRgnData == mpStdClipRgnData &&
1780                      mpClipRgnData->rdh.nCount == 1 )
1781                 {
1782                     RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1783 
1784                     aBuf.append( "\nnewpath\n" );
1785                     aBuf.append( pRect->left );
1786                     aBuf.append( " " );
1787                     aBuf.append( pRect->top );
1788                     aBuf.append( " moveto\n" );
1789                     aBuf.append( pRect->right );
1790                     aBuf.append( " " );
1791                     aBuf.append( pRect->top );
1792                     aBuf.append( " lineto\n" );
1793                     aBuf.append( pRect->right );
1794                     aBuf.append( " " );
1795                     aBuf.append( pRect->bottom );
1796                     aBuf.append( " lineto\n" );
1797                     aBuf.append( pRect->left );
1798                     aBuf.append( " " );
1799                     aBuf.append( pRect->bottom );
1800                     aBuf.append( " lineto\n"
1801                                  "closepath\n"
1802                                  "clip\n"
1803                                  "newpath\n" );
1804                 }
1805 
1806                 // #107797# Write out buffer
1807                 // ----------------------------------------------------------------------------------
1808 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1809 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1810 
1811 
1812                 // #107797# Write out EPS transformation code
1813                 // ----------------------------------------------------------------------------------
1814 				double	dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1815 				double	dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1816                 // reserve a sal_uInt16 again
1817                 aBuf.setLength( 2 );
1818                 aBuf.append( "\n\n[" );
1819                 aBuf.append( dM11 );
1820                 aBuf.append( " 0 0 " );
1821                 aBuf.append( dM22 );
1822                 aBuf.append( ' ' );
1823                 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1824                 aBuf.append( ' ' );
1825                 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1826                 aBuf.append( "] concat\n"
1827                              "%%BeginDocument:\n" );
1828 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1829 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1830 
1831 
1832                 // #107797# Write out actual EPS content
1833                 // ----------------------------------------------------------------------------------
1834 				sal_uLong	nToDo = nSize;
1835 				sal_uLong	nDoNow;
1836 				while ( nToDo )
1837 				{
1838 					nDoNow = nToDo;
1839 					if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1840 						nDoNow = POSTSCRIPT_BUFSIZE - 2;
1841                     // the following is based on the string buffer allocation
1842                     // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1843 					*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
1844 					memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
1845 					sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
1846 					if (!nResult )
1847 						break;
1848 					nToDo -= nResult;
1849 				}
1850 
1851 
1852                 // #107797# Write out EPS encapsulation footer
1853                 // ----------------------------------------------------------------------------------
1854                 // reserve a sal_uInt16 again
1855                 aBuf.setLength( 2 );
1856                 aBuf.append( "%%EndDocument\n"
1857                              "count op_count_salWin sub {pop} repeat\n"
1858                              "countdictstack dict_count_salWin sub {end} repeat\n"
1859                              "b4_Inc_state_salWin restore\n\n" );
1860 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1861 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1862 				bRetValue = TRUE;
1863 			}
1864 		}
1865 	}
1866 
1867 	return bRetValue;
1868 }
1869 
1870 // -----------------------------------------------------------------------
1871 
1872 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1873 {
1874     SystemGraphicsData aRes;
1875     aRes.nSize = sizeof(aRes);
1876     aRes.hDC = const_cast< WinSalGraphics* >(this)->getHDC();
1877     return aRes;
1878 }
1879 
1880 // -----------------------------------------------------------------------
1881