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