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