xref: /trunk/main/vcl/win/source/gdi/salgdi.cxx (revision a206ee714f966ac34d586aa0448e90cdf7eed74e)
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