xref: /trunk/main/vcl/win/source/gdi/salgdi.cxx (revision 86e1cf34)
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 
ImplInitSalGDI()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 
ImplFreeSalGDI()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 necessary
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 
ImplIsPaletteEntry(BYTE nRed,BYTE nGreen,BYTE nBlue)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 
ImplIsSysColorEntry(SalColor nSalColor)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 
ImplInsertSysColorEntry(int nSysIndex)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 
ImplUpdateSysColorEntries()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 
ImplGetROPSalColor(SalROPColor nROPColor)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 
ImplSalInitGraphics(WinSalGraphics * pData)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 
ImplSalDeInitGraphics(WinSalGraphics * pData)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 
ImplGetCachedDC(sal_uLong nID,HBITMAP hBmp)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 
ImplReleaseCachedDC(sal_uLong nID)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 
ImplClearHDCCache(SalData * pData)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
ImplPreparePolyDraw(bool bCloseFigures,sal_uLong nPoly,const sal_uLong * pPoints,const SalPoint * const * pPtAry,const BYTE * const * pFlgAry,POINT * pWinPointAry,BYTE * pWinFlagAry)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
ImplRenderPath(HDC hdc,sal_uLong nPoints,const SalPoint * pPtAry,const BYTE * pFlgAry)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 
WinSalGraphics()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 
~WinSalGraphics()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 
GetResolution(sal_Int32 & rDPIX,sal_Int32 & rDPIY)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 
GetBitCount()808 sal_uInt16 WinSalGraphics::GetBitCount()
809 {
810 	return (sal_uInt16)GetDeviceCaps( getHDC(), BITSPIXEL );
811 }
812 
813 // -----------------------------------------------------------------------
814 
GetGraphicsWidth() const815 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 
ResetClipRegion()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 
setClipRegion(const Region & i_rClip)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(0 == mpClipRgnData->rdh.nCount)
1021         {
1022             // #123585# region is empty; this may happen when e.g. a PolyPolygon is given
1023             // that contains no polygons or only empty ones (no width/height). This is
1024             // perfectly fine and we are done, except setting it (see end of method)
1025         }
1026         else if(1 == mpClipRgnData->rdh.nCount)
1027         {
1028             RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1029             mhRegion = CreateRectRgn( pRect->left, pRect->top,
1030                                                      pRect->right, pRect->bottom );
1031         }
1032         else if(mpClipRgnData->rdh.nCount > 1)
1033         {
1034             ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
1035             mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
1036 
1037             // if ExtCreateRegion(...) is not supported
1038             if( !mhRegion )
1039             {
1040                 RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData;
1041 
1042                 if( pHeader->nCount )
1043                 {
1044                     RECT* pRect = (RECT*) mpClipRgnData->Buffer;
1045                     mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
1046                     pRect++;
1047 
1048                     for( ULONG n = 1; n < pHeader->nCount; n++, pRect++ )
1049                     {
1050                         HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
1051                         CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR );
1052                         DeleteRegion( hRgn );
1053                     }
1054                 }
1055             }
1056 
1057             if ( mpClipRgnData != mpStdClipRgnData )
1058                 delete [] mpClipRgnData;
1059         }
1060 	}
1061 
1062 	if( mhRegion )
1063     {
1064         SelectClipRgn( getHDC(), mhRegion );
1065 
1066         // debug code if you weant to check range of the newly applied ClipRegion
1067         //RECT aBound;
1068         //const int aRegionType = GetRgnBox(mhRegion, &aBound);
1069         //
1070         //bool bBla = true;
1071     }
1072     else
1073     {
1074         // #123585# See above, this is a valid case, execute it
1075         SelectClipRgn( getHDC(), 0 );
1076     }
1077 
1078     // #123585# retval no longer dependent of mhRegion, see TaskId comments above
1079     return true;
1080 }
1081 
1082 // -----------------------------------------------------------------------
1083 
SetLineColor()1084 void WinSalGraphics::SetLineColor()
1085 {
1086 	// create and select new pen
1087 	HPEN hNewPen = GetStockPen( NULL_PEN );
1088 	HPEN hOldPen = SelectPen( getHDC(), hNewPen );
1089 
1090 	// destroy or save old pen
1091 	if ( mhPen )
1092 	{
1093 		if ( !mbStockPen )
1094 			DeletePen( mhPen );
1095 	}
1096 	else
1097 		mhDefPen = hOldPen;
1098 
1099 	// set new data
1100 	mhPen		= hNewPen;
1101 	mbPen		= FALSE;
1102 	mbStockPen	= TRUE;
1103 }
1104 
1105 // -----------------------------------------------------------------------
1106 
SetLineColor(SalColor nSalColor)1107 void WinSalGraphics::SetLineColor( SalColor nSalColor )
1108 {
1109     maLineColor = nSalColor;
1110 	COLORREF	nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
1111 										SALCOLOR_GREEN( nSalColor ),
1112 										SALCOLOR_BLUE( nSalColor ) );
1113 	HPEN		hNewPen = 0;
1114 	sal_Bool		bStockPen = FALSE;
1115 
1116 	// search for stock pen (only screen, because printer have problems,
1117 	// when we use stock objects)
1118 	if ( !mbPrinter )
1119 	{
1120 		SalData* pSalData = GetSalData();
1121 		for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ )
1122 		{
1123 			if ( nPenColor == pSalData->maStockPenColorAry[i] )
1124 			{
1125 				hNewPen = pSalData->mhStockPenAry[i];
1126 				bStockPen = TRUE;
1127 				break;
1128 			}
1129 		}
1130 	}
1131 
1132 	// create new pen
1133 	if ( !hNewPen )
1134 	{
1135 		if ( !mbPrinter )
1136 		{
1137 			if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
1138 				nPenColor = PALRGB_TO_RGB( nPenColor );
1139 		}
1140 
1141 		hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor );
1142 		bStockPen = FALSE;
1143 	}
1144 
1145 	// select new pen
1146 	HPEN hOldPen = SelectPen( getHDC(), hNewPen );
1147 
1148 	// destroy or save old pen
1149 	if ( mhPen )
1150 	{
1151 		if ( !mbStockPen )
1152 			DeletePen( mhPen );
1153 	}
1154 	else
1155 		mhDefPen = hOldPen;
1156 
1157 	// set new data
1158 	mnPenColor	= nPenColor;
1159 	mhPen		= hNewPen;
1160 	mbPen		= TRUE;
1161 	mbStockPen	= bStockPen;
1162 }
1163 
1164 // -----------------------------------------------------------------------
1165 
SetFillColor()1166 void WinSalGraphics::SetFillColor()
1167 {
1168 	// create and select new brush
1169 	HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
1170 	HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush );
1171 
1172 	// destroy or save old brush
1173 	if ( mhBrush )
1174 	{
1175 		if ( !mbStockBrush )
1176 			DeleteBrush( mhBrush );
1177 	}
1178 	else
1179 		mhDefBrush = hOldBrush;
1180 
1181 	// set new data
1182 	mhBrush		= hNewBrush;
1183 	mbBrush		= FALSE;
1184 	mbStockBrush = TRUE;
1185 }
1186 
1187 // -----------------------------------------------------------------------
1188 
SetFillColor(SalColor nSalColor)1189 void WinSalGraphics::SetFillColor( SalColor nSalColor )
1190 {
1191     maFillColor = nSalColor;
1192 	SalData*	pSalData	= GetSalData();
1193 	BYTE		nRed		= SALCOLOR_RED( nSalColor );
1194 	BYTE		nGreen		= SALCOLOR_GREEN( nSalColor );
1195 	BYTE		nBlue		= SALCOLOR_BLUE( nSalColor );
1196 	COLORREF	nBrushColor = PALETTERGB( nRed, nGreen, nBlue );
1197 	HBRUSH		hNewBrush	= 0;
1198 	sal_Bool		bStockBrush = FALSE;
1199 
1200 	// search for stock brush (only screen, because printer have problems,
1201 	// when we use stock objects)
1202 	if ( !mbPrinter )
1203 	{
1204 		for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ )
1205 		{
1206 			if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] )
1207 			{
1208 				hNewBrush = pSalData->mhStockBrushAry[i];
1209 				bStockBrush = TRUE;
1210 				break;
1211 			}
1212 		}
1213 	}
1214 
1215 	// create new brush
1216 	if ( !hNewBrush )
1217 	{
1218 		if ( mbPrinter || !pSalData->mhDitherDIB )
1219 			hNewBrush = CreateSolidBrush( nBrushColor );
1220 		else
1221 		{
1222 			if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount )
1223 			{
1224 				BYTE* pTmp = pSalData->mpDitherDIBData;
1225 				long* pDitherDiff = pSalData->mpDitherDiff;
1226 				BYTE* pDitherLow = pSalData->mpDitherLow;
1227 				BYTE* pDitherHigh = pSalData->mpDitherHigh;
1228 
1229 				for( long nY = 0L; nY < 8L; nY++ )
1230 				{
1231 					for( long nX = 0L; nX < 8L; nX++ )
1232 					{
1233 						const long nThres = aOrdDither16Bit[ nY ][ nX ];
1234 						*pTmp++ = DMAP( nBlue, nThres );
1235 						*pTmp++ = DMAP( nGreen, nThres );
1236 						*pTmp++ = DMAP( nRed, nThres );
1237 					}
1238 				}
1239 
1240 				hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS );
1241 			}
1242 			else if ( ImplIsSysColorEntry( nSalColor ) )
1243 			{
1244 				nBrushColor = PALRGB_TO_RGB( nBrushColor );
1245 				hNewBrush = CreateSolidBrush( nBrushColor );
1246 			}
1247 			else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) )
1248 				hNewBrush = CreateSolidBrush( nBrushColor );
1249 			else
1250 			{
1251 				BYTE* pTmp = pSalData->mpDitherDIBData;
1252 				long* pDitherDiff = pSalData->mpDitherDiff;
1253 				BYTE* pDitherLow = pSalData->mpDitherLow;
1254 				BYTE* pDitherHigh = pSalData->mpDitherHigh;
1255 
1256 				for ( long nY = 0L; nY < 8L; nY++ )
1257 				{
1258 					for ( long nX = 0L; nX < 8L; nX++ )
1259 					{
1260 						const long nThres = aOrdDither8Bit[ nY ][ nX ];
1261 						*pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36;
1262 						pTmp++;
1263 					}
1264 				}
1265 
1266 				hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
1267 			}
1268 		}
1269 
1270 		bStockBrush = FALSE;
1271 	}
1272 
1273 	// select new brush
1274 	HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush );
1275 
1276 	// destroy or save old brush
1277 	if ( mhBrush )
1278 	{
1279 		if ( !mbStockBrush )
1280 			DeleteBrush( mhBrush );
1281 	}
1282 	else
1283 		mhDefBrush = hOldBrush;
1284 
1285 	// set new data
1286 	mnBrushColor = nBrushColor;
1287 	mhBrush		= hNewBrush;
1288 	mbBrush		= TRUE;
1289 	mbStockBrush = bStockBrush;
1290 }
1291 
1292 // -----------------------------------------------------------------------
1293 
SetXORMode(bool bSet,bool)1294 void WinSalGraphics::SetXORMode( bool bSet, bool )
1295 {
1296 	mbXORMode = bSet;
1297 	::SetROP2( getHDC(), bSet ? R2_XORPEN : R2_COPYPEN );
1298 }
1299 
1300 // -----------------------------------------------------------------------
1301 
SetROPLineColor(SalROPColor nROPColor)1302 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
1303 {
1304 	SetLineColor( ImplGetROPSalColor( nROPColor ) );
1305 }
1306 
1307 // -----------------------------------------------------------------------
1308 
SetROPFillColor(SalROPColor nROPColor)1309 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
1310 {
1311 	SetFillColor( ImplGetROPSalColor( nROPColor ) );
1312 }
1313 
1314 // -----------------------------------------------------------------------
1315 
drawPixel(long nX,long nY)1316 void WinSalGraphics::drawPixel( long nX, long nY )
1317 {
1318 	if ( mbXORMode )
1319 	{
1320 		HBRUSH	hBrush = CreateSolidBrush( mnPenColor );
1321 		HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1322 		PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1323 		SelectBrush( getHDC(), hOldBrush );
1324 		DeleteBrush( hBrush );
1325 	}
1326 	else
1327 		SetPixel( getHDC(), (int)nX, (int)nY, mnPenColor );
1328 }
1329 
1330 // -----------------------------------------------------------------------
1331 
drawPixel(long nX,long nY,SalColor nSalColor)1332 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
1333 {
1334 	COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1335 								SALCOLOR_GREEN( nSalColor ),
1336 								SALCOLOR_BLUE( nSalColor ) );
1337 
1338 	if ( !mbPrinter &&
1339 		 GetSalData()->mhDitherPal &&
1340 		 ImplIsSysColorEntry( nSalColor ) )
1341 		nCol = PALRGB_TO_RGB( nCol );
1342 
1343 	if ( mbXORMode )
1344 	{
1345 		HBRUSH	hBrush = CreateSolidBrush( nCol );
1346 		HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1347 		PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1348 		SelectBrush( getHDC(), hOldBrush );
1349 		DeleteBrush( hBrush );
1350 	}
1351 	else
1352 		::SetPixel( getHDC(), (int)nX, (int)nY, nCol );
1353 }
1354 
1355 // -----------------------------------------------------------------------
1356 
drawLine(long nX1,long nY1,long nX2,long nY2)1357 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
1358 {
1359 	MoveToEx( getHDC(), (int)nX1, (int)nY1, NULL );
1360 
1361 	// we must paint the endpoint
1362 	int bPaintEnd = TRUE;
1363 	if ( nX1 == nX2 )
1364 	{
1365 		bPaintEnd = FALSE;
1366 		if ( nY1 <= nY2 )
1367 			nY2++;
1368 		else
1369 			nY2--;
1370 	}
1371 	if ( nY1 == nY2 )
1372 	{
1373 		bPaintEnd = FALSE;
1374 		if ( nX1 <= nX2 )
1375 			nX2++;
1376 		else
1377 			nX2--;
1378 	}
1379 
1380 	LineTo( getHDC(), (int)nX2, (int)nY2 );
1381 
1382 	if ( bPaintEnd && !mbPrinter )
1383 	{
1384 		if ( mbXORMode )
1385 		{
1386 			HBRUSH	hBrush = CreateSolidBrush( mnPenColor );
1387 			HBRUSH	hOldBrush = SelectBrush( getHDC(), hBrush );
1388 			PatBlt( getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
1389 			SelectBrush( getHDC(), hOldBrush );
1390 			DeleteBrush( hBrush );
1391 		}
1392 		else
1393 			SetPixel( getHDC(), (int)nX2, (int)nY2, mnPenColor );
1394 	}
1395 }
1396 
1397 // -----------------------------------------------------------------------
1398 
drawRect(long nX,long nY,long nWidth,long nHeight)1399 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
1400 {
1401 	if ( !mbPen )
1402 	{
1403 		if ( !mbPrinter )
1404 		{
1405 			PatBlt( getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight,
1406 					mbXORMode ? PATINVERT : PATCOPY );
1407 		}
1408 		else
1409 		{
1410 			RECT aWinRect;
1411 			aWinRect.left	= nX;
1412 			aWinRect.top	= nY;
1413 			aWinRect.right	= nX+nWidth;
1414 			aWinRect.bottom = nY+nHeight;
1415 			::FillRect( getHDC(), &aWinRect, mhBrush );
1416 		}
1417 	}
1418 	else
1419 		WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
1420 }
1421 
1422 // -----------------------------------------------------------------------
1423 
drawPolyLine(sal_uInt32 nPoints,const SalPoint * pPtAry)1424 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry )
1425 {
1426 	// Unter NT koennen wir das Array direkt weiterreichen
1427 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1428 				"WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
1429 
1430 	POINT* pWinPtAry = (POINT*)pPtAry;
1431 	// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1432 	// von Punkten
1433 	if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1434 		Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
1435 }
1436 
1437 // -----------------------------------------------------------------------
1438 
drawPolygon(sal_uInt32 nPoints,const SalPoint * pPtAry)1439 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
1440 {
1441 	// Unter NT koennen wir das Array direkt weiterreichen
1442 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1443 				"WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
1444 
1445 	POINT* pWinPtAry = (POINT*)pPtAry;
1446 	// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
1447 	// von Punkten
1448 	if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1449 		WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
1450 }
1451 
1452 // -----------------------------------------------------------------------
1453 
drawPolyPolygon(sal_uInt32 nPoly,const sal_uInt32 * pPoints,PCONSTSALPOINT * pPtAry)1454 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1455 								   PCONSTSALPOINT* pPtAry )
1456 {
1457 	UINT	aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF];
1458 	UINT*	pWinPointAry;
1459 	UINT	nPolyPolyPoints = 0;
1460 	UINT	nPoints;
1461 	UINT	i;
1462 
1463 	if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
1464 		pWinPointAry = aWinPointAry;
1465 	else
1466 		pWinPointAry = new UINT[nPoly];
1467 
1468 	for ( i = 0; i < (UINT)nPoly; i++ )
1469 	{
1470 		nPoints = (UINT)pPoints[i]+1;
1471 		pWinPointAry[i] = nPoints;
1472 		nPolyPolyPoints += nPoints;
1473 	}
1474 
1475 	POINT  aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF];
1476 	POINT* pWinPointAryAry;
1477 	if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF )
1478 		pWinPointAryAry = aWinPointAryAry;
1479 	else
1480 		pWinPointAryAry = new POINT[nPolyPolyPoints];
1481 	// Unter NT koennen wir das Array direkt weiterreichen
1482 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1483 				"WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" );
1484 	const SalPoint* pPolyAry;
1485 	UINT			n = 0;
1486 	for ( i = 0; i < (UINT)nPoly; i++ )
1487 	{
1488 		nPoints = pWinPointAry[i];
1489 		pPolyAry = pPtAry[i];
1490 		memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) );
1491 		pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n];
1492 		n += nPoints;
1493 	}
1494 
1495 	if ( !WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
1496 		 (nPolyPolyPoints > MAX_64KSALPOINTS) )
1497 	{
1498 		nPolyPolyPoints  = 0;
1499 		nPoly = 0;
1500 		do
1501 		{
1502 			nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
1503 			nPoly++;
1504 		}
1505 		while ( nPolyPolyPoints < MAX_64KSALPOINTS );
1506 		nPoly--;
1507 		if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
1508 			pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
1509 		if ( nPoly == 1 )
1510 			WIN_Polygon( getHDC(), pWinPointAryAry, *pWinPointAry );
1511 		else
1512 			WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly );
1513 	}
1514 
1515 	if ( pWinPointAry != aWinPointAry )
1516 		delete [] pWinPointAry;
1517 	if ( pWinPointAryAry != aWinPointAryAry )
1518 		delete [] pWinPointAryAry;
1519 }
1520 
1521 // -----------------------------------------------------------------------
1522 
1523 #define SAL_POLY_STACKBUF		32
1524 
1525 // -----------------------------------------------------------------------
1526 
drawPolyLineBezier(sal_uInt32 nPoints,const SalPoint * pPtAry,const BYTE * pFlgAry)1527 sal_Bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1528 {
1529 #ifdef USE_GDI_BEZIERS
1530 	// Unter NT koennen wir das Array direkt weiterreichen
1531 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1532 				"WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
1533 
1534     ImplRenderPath( getHDC(), nPoints, pPtAry, pFlgAry );
1535 
1536     return sal_True;
1537 #else
1538     return sal_False;
1539 #endif
1540 }
1541 
1542 // -----------------------------------------------------------------------
1543 
drawPolygonBezier(sal_uInt32 nPoints,const SalPoint * pPtAry,const BYTE * pFlgAry)1544 sal_Bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1545 {
1546 #ifdef USE_GDI_BEZIERS
1547 	// Unter NT koennen wir das Array direkt weiterreichen
1548 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1549 				"WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" );
1550 
1551     POINT	aStackAry1[SAL_POLY_STACKBUF];
1552     BYTE	aStackAry2[SAL_POLY_STACKBUF];
1553     POINT* 	pWinPointAry;
1554     BYTE* 	pWinFlagAry;
1555     if( nPoints > SAL_POLY_STACKBUF )
1556     {
1557         pWinPointAry = new POINT[ nPoints ];
1558         pWinFlagAry = new BYTE[ nPoints ];
1559     }
1560     else
1561     {
1562         pWinPointAry = aStackAry1;
1563         pWinFlagAry = aStackAry2;
1564     }
1565 
1566     ImplPreparePolyDraw(true, 1, &nPoints, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
1567 
1568     sal_Bool bRet( sal_False );
1569 
1570     if( BeginPath( getHDC() ) )
1571     {
1572         PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nPoints);
1573 
1574         if( EndPath( getHDC() ) )
1575         {
1576             if( StrokeAndFillPath( getHDC() ) )
1577                 bRet = sal_True;
1578         }
1579     }
1580 
1581     if( pWinPointAry != aStackAry1 )
1582     {
1583         delete [] pWinPointAry;
1584         delete [] pWinFlagAry;
1585     }
1586 
1587     return bRet;
1588 #else
1589     return sal_False;
1590 #endif
1591 }
1592 
1593 // -----------------------------------------------------------------------
1594 
drawPolyPolygonBezier(sal_uInt32 nPoly,const sal_uInt32 * pPoints,const SalPoint * const * pPtAry,const BYTE * const * pFlgAry)1595 sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1596                                              const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
1597 {
1598 #ifdef USE_GDI_BEZIERS
1599 	// Unter NT koennen wir das Array direkt weiterreichen
1600 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1601 				"WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
1602 
1603     sal_uLong nCurrPoly, nTotalPoints;
1604     const sal_uLong* pCurrPoints = pPoints;
1605     for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
1606         nTotalPoints += *pCurrPoints++;
1607 
1608     POINT	aStackAry1[SAL_POLY_STACKBUF];
1609     BYTE	aStackAry2[SAL_POLY_STACKBUF];
1610     POINT* 	pWinPointAry;
1611     BYTE* 	pWinFlagAry;
1612     if( nTotalPoints > SAL_POLY_STACKBUF )
1613     {
1614         pWinPointAry = new POINT[ nTotalPoints ];
1615         pWinFlagAry = new BYTE[ nTotalPoints ];
1616     }
1617     else
1618     {
1619         pWinPointAry = aStackAry1;
1620         pWinFlagAry = aStackAry2;
1621     }
1622 
1623     ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
1624 
1625     sal_Bool bRet( sal_False );
1626 
1627     if( BeginPath( getHDC() ) )
1628     {
1629         PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints);
1630 
1631         if( EndPath( getHDC() ) )
1632         {
1633             if( StrokeAndFillPath( getHDC() ) )
1634                 bRet = sal_True;
1635         }
1636     }
1637 
1638     if( pWinPointAry != aStackAry1 )
1639     {
1640         delete [] pWinPointAry;
1641         delete [] pWinFlagAry;
1642     }
1643 
1644     return bRet;
1645 #else
1646     return sal_False;
1647 #endif
1648 }
1649 
1650 // -----------------------------------------------------------------------
1651 
1652 #define POSTSCRIPT_BUFSIZE 0x4000			// MAXIMUM BUFSIZE EQ 0xFFFF
1653 #define POSTSCRIPT_BOUNDINGSEARCH 0x1000	// we only try to get the BoundingBox
1654 											// in the first 4096 bytes
1655 
ImplSearchEntry(BYTE * pSource,BYTE * pDest,sal_uLong nComp,sal_uLong nSize)1656 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize )
1657 {
1658 	while ( nComp-- >= nSize )
1659 	{
1660 		sal_uLong i;
1661 		for ( i = 0; i < nSize; i++ )
1662 		{
1663 			if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
1664 				break;
1665 		}
1666 		if ( i == nSize )
1667 			return pSource;
1668 		pSource++;
1669 	}
1670 	return NULL;
1671 }
1672 
ImplGetBoundingBox(double * nNumb,BYTE * pSource,sal_uLong nSize)1673 static sal_Bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
1674 {
1675 	sal_Bool	bRetValue = FALSE;
1676 	BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
1677 	if ( pDest )
1678 	{
1679 		nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
1680 		pDest += 14;
1681 
1682 		int nSizeLeft = nSize - ( pDest - pSource );
1683 		if ( nSizeLeft > 100 )
1684 			nSizeLeft = 100;	// only 100 bytes following the bounding box will be checked
1685 
1686 		int i;
1687 		for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
1688 		{
1689 			int 	nDivision = 1;
1690 			sal_Bool	bDivision = FALSE;
1691 			sal_Bool	bNegative = FALSE;
1692 			sal_Bool	bValid = TRUE;
1693 
1694 			while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
1695 			BYTE nByte = *pDest;
1696 			while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
1697 			{
1698 				switch ( nByte )
1699 				{
1700 					case '.' :
1701 						if ( bDivision )
1702 							bValid = FALSE;
1703 						else
1704 							bDivision = TRUE;
1705 						break;
1706 					case '-' :
1707 						bNegative = TRUE;
1708 						break;
1709 					default :
1710 						if ( ( nByte < '0' ) || ( nByte > '9' ) )
1711 							nSizeLeft = 1; 	// error parsing the bounding box values
1712 						else if ( bValid )
1713 						{
1714 							if ( bDivision )
1715 								nDivision*=10;
1716 							nNumb[i] *= 10;
1717 							nNumb[i] += nByte - '0';
1718 						}
1719 						break;
1720 				}
1721 				nSizeLeft--;
1722 				nByte = *(++pDest);
1723 			}
1724 			if ( bNegative )
1725 				nNumb[i] = -nNumb[i];
1726 			if ( bDivision && ( nDivision != 1 ) )
1727 				nNumb[i] /= nDivision;
1728 		}
1729 		if ( i == 4 )
1730 			bRetValue = TRUE;
1731 	}
1732 	return bRetValue;
1733 }
1734 
drawEPS(long nX,long nY,long nWidth,long nHeight,void * pPtr,sal_uLong nSize)1735 sal_Bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
1736 {
1737 	sal_Bool bRetValue = FALSE;
1738 
1739 	if ( mbPrinter )
1740 	{
1741 		int nEscape = POSTSCRIPT_PASSTHROUGH;
1742 
1743 		if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
1744 		{
1745 			double	nBoundingBox[4];
1746 
1747 			if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
1748 			{
1749                 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1750 
1751                 // reserve place for a sal_uInt16
1752                 aBuf.append( "aa" );
1753 
1754                 // #107797# Write out EPS encapsulation header
1755                 // ----------------------------------------------------------------------------------
1756 
1757                 // directly taken from the PLRM 3.0, p. 726. Note:
1758                 // this will definitely cause problems when
1759                 // recursively creating and embedding PostScript files
1760                 // in OOo, since we use statically-named variables
1761                 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1762                 // op_count_salWin). Currently, I have no idea on how to
1763                 // work around that, except from scanning and
1764                 // interpreting the EPS for unused identifiers.
1765 
1766                 // append the real text
1767                 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1768                              "/dict_count_salWin countdictstack def\n"
1769                              "/op_count_salWin count 1 sub def\n"
1770                              "userdict begin\n"
1771                              "/showpage {} def\n"
1772                              "0 setgray 0 setlinecap\n"
1773                              "1 setlinewidth 0 setlinejoin\n"
1774                              "10 setmiterlimit [] 0 setdash newpath\n"
1775                              "/languagelevel where\n"
1776                              "{\n"
1777                              "  pop languagelevel\n"
1778                              "  1 ne\n"
1779                              "  {\n"
1780                              "    false setstrokeadjust false setoverprint\n"
1781                              "  } if\n"
1782                              "} if\n\n" );
1783 
1784 
1785                 // #i10737# Apply clipping manually
1786                 // ----------------------------------------------------------------------------------
1787 
1788                 // Windows seems to ignore any clipping at the HDC,
1789                 // when followed by a POSTSCRIPT_PASSTHROUGH
1790 
1791                 // Check whether we've got a clipping, consisting of
1792                 // exactly one rect (other cases should be, but aren't
1793                 // handled currently)
1794 
1795                 // TODO: Handle more than one rectangle here (take
1796                 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1797                 // characters!)
1798                 if ( mhRegion != 0 &&
1799                      mpStdClipRgnData != NULL &&
1800                      mpClipRgnData == mpStdClipRgnData &&
1801                      mpClipRgnData->rdh.nCount == 1 )
1802                 {
1803                     RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1804 
1805                     aBuf.append( "\nnewpath\n" );
1806                     aBuf.append( pRect->left );
1807                     aBuf.append( " " );
1808                     aBuf.append( pRect->top );
1809                     aBuf.append( " moveto\n" );
1810                     aBuf.append( pRect->right );
1811                     aBuf.append( " " );
1812                     aBuf.append( pRect->top );
1813                     aBuf.append( " lineto\n" );
1814                     aBuf.append( pRect->right );
1815                     aBuf.append( " " );
1816                     aBuf.append( pRect->bottom );
1817                     aBuf.append( " lineto\n" );
1818                     aBuf.append( pRect->left );
1819                     aBuf.append( " " );
1820                     aBuf.append( pRect->bottom );
1821                     aBuf.append( " lineto\n"
1822                                  "closepath\n"
1823                                  "clip\n"
1824                                  "newpath\n" );
1825                 }
1826 
1827                 // #107797# Write out buffer
1828                 // ----------------------------------------------------------------------------------
1829 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1830 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1831 
1832 
1833                 // #107797# Write out EPS transformation code
1834                 // ----------------------------------------------------------------------------------
1835 				double	dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1836 				double	dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1837                 // reserve a sal_uInt16 again
1838                 aBuf.setLength( 2 );
1839                 aBuf.append( "\n\n[" );
1840                 aBuf.append( dM11 );
1841                 aBuf.append( " 0 0 " );
1842                 aBuf.append( dM22 );
1843                 aBuf.append( ' ' );
1844                 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1845                 aBuf.append( ' ' );
1846                 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1847                 aBuf.append( "] concat\n"
1848                              "%%BeginDocument:\n" );
1849 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1850 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1851 
1852 
1853                 // #107797# Write out actual EPS content
1854                 // ----------------------------------------------------------------------------------
1855 				sal_uLong	nToDo = nSize;
1856 				sal_uLong	nDoNow;
1857 				while ( nToDo )
1858 				{
1859 					nDoNow = nToDo;
1860 					if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1861 						nDoNow = POSTSCRIPT_BUFSIZE - 2;
1862                     // the following is based on the string buffer allocation
1863                     // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1864 					*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
1865 					memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
1866 					sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
1867 					if (!nResult )
1868 						break;
1869 					nToDo -= nResult;
1870 				}
1871 
1872 
1873                 // #107797# Write out EPS encapsulation footer
1874                 // ----------------------------------------------------------------------------------
1875                 // reserve a sal_uInt16 again
1876                 aBuf.setLength( 2 );
1877                 aBuf.append( "%%EndDocument\n"
1878                              "count op_count_salWin sub {pop} repeat\n"
1879                              "countdictstack dict_count_salWin sub {end} repeat\n"
1880                              "b4_Inc_state_salWin restore\n\n" );
1881 				*((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1882 				Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1883 				bRetValue = TRUE;
1884 			}
1885 		}
1886 	}
1887 
1888 	return bRetValue;
1889 }
1890 
1891 // -----------------------------------------------------------------------
1892 
GetGraphicsData() const1893 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1894 {
1895     SystemGraphicsData aRes;
1896     aRes.nSize = sizeof(aRes);
1897     aRes.hDC = const_cast< WinSalGraphics* >(this)->getHDC();
1898     return aRes;
1899 }
1900 
1901 // -----------------------------------------------------------------------
1902