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