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