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