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