Bump version to 4.1-6
[LibreOffice.git] / vcl / win / source / gdi / salgdi.cxx
blob7bba68e43354568134f659ce72915e8dc6996979
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <stdio.h>
22 #include <string.h>
24 #include <svsys.h>
25 #include <rtl/strbuf.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/poly.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
33 #include <win/wincomp.hxx>
34 #include <win/saldata.hxx>
35 #include <win/salgdi.h>
36 #include <win/salframe.h>
38 #include <region.h>
40 // =======================================================================
42 // comment out to prevent use of beziers on GDI functions
43 #define USE_GDI_BEZIERS
45 // =======================================================================
47 #define DITHER_PAL_DELTA 51
48 #define DITHER_PAL_STEPS 6
49 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
50 #define DITHER_MAX_SYSCOLOR 16
51 #define DITHER_EXTRA_COLORS 1
52 #define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
54 // =======================================================================
56 struct SysColorEntry
58 DWORD nRGB;
59 SysColorEntry* pNext;
62 // =======================================================================
64 static SysColorEntry* pFirstSysColor = NULL;
65 static SysColorEntry* pActSysColor = NULL;
67 // -----------------------------------------------------------------------------
69 // Blue7
70 static PALETTEENTRY aImplExtraColor1 =
72 0, 184, 255, 0
75 // -----------------------------------------------------------------------------
77 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
79 { 0, 0, 0, 0 },
80 { 0, 0, 0x80, 0 },
81 { 0, 0x80, 0, 0 },
82 { 0, 0x80, 0x80, 0 },
83 { 0x80, 0, 0, 0 },
84 { 0x80, 0, 0x80, 0 },
85 { 0x80, 0x80, 0, 0 },
86 { 0x80, 0x80, 0x80, 0 },
87 { 0xC0, 0xC0, 0xC0, 0 },
88 { 0, 0, 0xFF, 0 },
89 { 0, 0xFF, 0, 0 },
90 { 0, 0xFF, 0xFF, 0 },
91 { 0xFF, 0, 0, 0 },
92 { 0xFF, 0, 0xFF, 0 },
93 { 0xFF, 0xFF, 0, 0 },
94 { 0xFF, 0xFF, 0xFF, 0 }
97 // -----------------------------------------------------------------------------
99 static BYTE aOrdDither8Bit[8][8] =
101 { 0, 38, 9, 48, 2, 40, 12, 50 },
102 { 25, 12, 35, 22, 28, 15, 37, 24 },
103 { 6, 44, 3, 41, 8, 47, 5, 44 },
104 { 32, 19, 28, 16, 34, 21, 31, 18 },
105 { 1, 40, 11, 49, 0, 39, 10, 48 },
106 { 27, 14, 36, 24, 26, 13, 36, 23 },
107 { 8, 46, 4, 43, 7, 45, 4, 42 },
108 { 33, 20, 30, 17, 32, 20, 29, 16 }
111 // -----------------------------------------------------------------------------
113 static BYTE aOrdDither16Bit[8][8] =
115 { 0, 6, 1, 7, 0, 6, 1, 7 },
116 { 4, 2, 5, 3, 4, 2, 5, 3 },
117 { 1, 7, 0, 6, 1, 7, 0, 6 },
118 { 5, 3, 4, 2, 5, 3, 4, 2 },
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 }
125 // =======================================================================
127 // we must create pens with 1-pixel width; otherwise the S3-graphics card
128 // map has many paint problems when drawing polygons/polyLines and a
129 // complex is set
130 #define GSL_PEN_WIDTH 1
132 // =======================================================================
134 #define SAL_POLYPOLYCOUNT_STACKBUF 8
135 #define SAL_POLYPOLYPOINTS_STACKBUF 64
137 // =======================================================================
139 void ImplInitSalGDI()
141 SalData* pSalData = GetSalData();
143 // init stock brushes
144 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
145 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
146 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
147 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
148 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
149 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
150 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
151 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
152 pSalData->mnStockPenCount = 4;
154 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
155 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
156 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
157 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
158 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
159 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
160 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
161 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
162 pSalData->mnStockBrushCount = 4;
164 // initialize cache of device contexts
165 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
166 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
168 // initialize temporary font list
169 pSalData->mpTempFontItem = NULL;
171 // support palettes for 256 color displays
172 HDC hDC = GetDC( 0 );
173 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
174 int nPlanes = GetDeviceCaps( hDC, PLANES );
175 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
176 int nBitCount = nBitsPixel * nPlanes;
178 if ( (nBitCount > 8) && (nBitCount < 24) )
180 // test, if we have to dither
181 HDC hMemDC = ::CreateCompatibleDC( hDC );
182 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
183 HBITMAP hBmpOld = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
184 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
185 HBRUSH hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
186 sal_Bool bDither16 = TRUE;
188 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
189 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
191 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
192 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
193 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
194 bDither16 = FALSE;
196 ::SelectObject( hMemDC, hBrushOld ), ::DeleteObject( hMemBrush );
197 ::SelectObject( hMemDC, hBmpOld ), ::DeleteObject( hMemBmp );
198 ::DeleteDC( hMemDC );
200 if( bDither16 )
202 // create DIBPattern for 16Bit dithering
203 long n;
205 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
206 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
207 pSalData->mpDitherDiff = new long[ 256 ];
208 pSalData->mpDitherLow = new BYTE[ 256 ];
209 pSalData->mpDitherHigh = new BYTE[ 256 ];
210 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
211 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
213 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
215 pBIH->biSize = sizeof( BITMAPINFOHEADER );
216 pBIH->biWidth = 8;
217 pBIH->biHeight = 8;
218 pBIH->biPlanes = 1;
219 pBIH->biBitCount = 24;
221 for( n = 0; n < 256L; n++ )
222 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
224 for( n = 0; n < 256L; n++ )
225 pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
227 for( n = 0; n < 256L; n++ )
228 pSalData->mpDitherHigh[ n ] = (BYTE) std::min( pSalData->mpDitherLow[ n ] + 8L, 255L );
231 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
233 BYTE nRed, nGreen, nBlue;
234 BYTE nR, nG, nB;
235 PALETTEENTRY* pPalEntry;
236 LOGPALETTE* pLogPal;
237 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
238 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
240 // create logical palette
241 pLogPal = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
242 pLogPal->palVersion = 0x0300;
243 pLogPal->palNumEntries = (sal_uInt16) nTotalCount;
244 pPalEntry = pLogPal->palPalEntry;
246 // Standard colors
247 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
248 pPalEntry += DITHER_MAX_SYSCOLOR;
250 // own palette (6/6/6)
251 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
253 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
255 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
257 pPalEntry->peRed = nRed;
258 pPalEntry->peGreen = nGreen;
259 pPalEntry->peBlue = nBlue;
260 pPalEntry->peFlags = 0;
261 pPalEntry++;
266 // insert special 'Blue' as standard drawing color
267 *pPalEntry++ = aImplExtraColor1;
269 // create palette
270 pSalData->mhDitherPal = CreatePalette( pLogPal );
271 delete[] (char*) pLogPal;
273 if( pSalData->mhDitherPal )
275 // create DIBPattern for 8Bit dithering
276 long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
277 long n;
279 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
280 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
281 pSalData->mpDitherDiff = new long[ 256 ];
282 pSalData->mpDitherLow = new BYTE[ 256 ];
283 pSalData->mpDitherHigh = new BYTE[ 256 ];
284 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
285 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
287 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
288 short* pColors = (short*) ( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
290 pBIH->biSize = sizeof( BITMAPINFOHEADER );
291 pBIH->biWidth = 8;
292 pBIH->biHeight = 8;
293 pBIH->biPlanes = 1;
294 pBIH->biBitCount = 8;
296 for( n = 0; n < nDitherPalCount; n++ )
297 pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
299 for( n = 0; n < 256L; n++ )
300 pSalData->mpDitherDiff[ n ] = n % 51L;
302 for( n = 0; n < 256L; n++ )
303 pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
305 for( n = 0; n < 256L; n++ )
306 pSalData->mpDitherHigh[ n ] = (BYTE)std::min( pSalData->mpDitherLow[ n ] + 1, 5 );
309 // get system color entries
310 ImplUpdateSysColorEntries();
313 ReleaseDC( 0, hDC );
316 // -----------------------------------------------------------------------
318 void ImplFreeSalGDI()
320 SalData* pSalData = GetSalData();
322 // destroy stock objects
323 int i;
324 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
325 DeletePen( pSalData->mhStockPenAry[i] );
326 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
327 DeleteBrush( pSalData->mhStockBrushAry[i] );
329 // delete 50% Brush
330 if ( pSalData->mh50Brush )
332 DeleteBrush( pSalData->mh50Brush );
333 pSalData->mh50Brush = 0;
336 // delete 50% Bitmap
337 if ( pSalData->mh50Bmp )
339 DeleteBitmap( pSalData->mh50Bmp );
340 pSalData->mh50Bmp = 0;
343 ImplClearHDCCache( pSalData );
344 delete[] pSalData->mpHDCCache;
346 // delete Ditherpalette, if existing
347 if ( pSalData->mhDitherPal )
349 DeleteObject( pSalData->mhDitherPal );
350 pSalData->mhDitherPal = 0;
353 // delete buffers for dithering DIB patterns, if necessary
354 if ( pSalData->mhDitherDIB )
356 GlobalUnlock( pSalData->mhDitherDIB );
357 GlobalFree( pSalData->mhDitherDIB );
358 pSalData->mhDitherDIB = 0;
359 delete[] pSalData->mpDitherDiff;
360 delete[] pSalData->mpDitherLow;
361 delete[] pSalData->mpDitherHigh;
364 // delete SysColorList
365 SysColorEntry* pEntry = pFirstSysColor;
366 while( pEntry )
368 SysColorEntry* pTmp = pEntry->pNext;
369 delete pEntry;
370 pEntry = pTmp;
372 pFirstSysColor = NULL;
374 // delete icon cache
375 SalIcon* pIcon = pSalData->mpFirstIcon;
376 pSalData->mpFirstIcon = NULL;
377 while( pIcon )
379 SalIcon* pTmp = pIcon->pNext;
380 DestroyIcon( pIcon->hIcon );
381 DestroyIcon( pIcon->hSmallIcon );
382 delete pIcon;
383 pIcon = pTmp;
386 // delete temporary font list
387 ImplReleaseTempFonts( *pSalData );
390 // -----------------------------------------------------------------------
392 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
394 // dither color?
395 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
396 return TRUE;
398 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
400 // standard palette color?
401 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
403 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
404 return TRUE;
407 // extra color?
408 if ( aImplExtraColor1.peRed == nRed &&
409 aImplExtraColor1.peGreen == nGreen &&
410 aImplExtraColor1.peBlue == nBlue )
412 return TRUE;
415 return FALSE;
418 // =======================================================================
420 int ImplIsSysColorEntry( SalColor nSalColor )
422 SysColorEntry* pEntry = pFirstSysColor;
423 const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
424 SALCOLOR_GREEN( nSalColor ),
425 SALCOLOR_BLUE( nSalColor ) );
427 while ( pEntry )
429 if ( pEntry->nRGB == nTestRGB )
430 return TRUE;
431 pEntry = pEntry->pNext;
434 return FALSE;
437 // =======================================================================
439 static void ImplInsertSysColorEntry( int nSysIndex )
441 const DWORD nRGB = GetSysColor( nSysIndex );
443 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
445 if ( !pFirstSysColor )
447 pActSysColor = pFirstSysColor = new SysColorEntry;
448 pFirstSysColor->nRGB = nRGB;
449 pFirstSysColor->pNext = NULL;
451 else
453 pActSysColor = pActSysColor->pNext = new SysColorEntry;
454 pActSysColor->nRGB = nRGB;
455 pActSysColor->pNext = NULL;
460 // =======================================================================
462 void ImplUpdateSysColorEntries()
464 // delete old SysColorList
465 SysColorEntry* pEntry = pFirstSysColor;
466 while( pEntry )
468 SysColorEntry* pTmp = pEntry->pNext;
469 delete pEntry;
470 pEntry = pTmp;
472 pActSysColor = pFirstSysColor = NULL;
474 // create new sys color list
475 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
476 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
477 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
478 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
479 ImplInsertSysColorEntry( COLOR_3DFACE );
480 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
481 ImplInsertSysColorEntry( COLOR_3DLIGHT );
482 ImplInsertSysColorEntry( COLOR_3DSHADOW );
483 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
484 ImplInsertSysColorEntry( COLOR_INFOBK );
485 ImplInsertSysColorEntry( COLOR_INFOTEXT );
486 ImplInsertSysColorEntry( COLOR_BTNTEXT );
487 ImplInsertSysColorEntry( COLOR_WINDOW );
488 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
489 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
490 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
491 ImplInsertSysColorEntry( COLOR_MENU );
492 ImplInsertSysColorEntry( COLOR_MENUTEXT );
493 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
494 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
495 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
496 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
499 // -----------------------------------------------------------------------
501 static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
503 SalColor nSalColor;
504 if ( nROPColor == SAL_ROP_0 )
505 nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
506 else
507 nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
508 return nSalColor;
511 // =======================================================================
513 void ImplSalInitGraphics( WinSalGraphics* pData )
515 // calculate the minimal line width for the printer
516 if ( pData->mbPrinter )
518 int nDPIX = GetDeviceCaps( pData->mhDC, LOGPIXELSX );
519 if ( nDPIX <= 300 )
520 pData->mnPenWidth = 0;
521 else
522 pData->mnPenWidth = nDPIX/300;
525 ::SetTextAlign( pData->mhDC, TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
526 ::SetBkMode( pData->mhDC, TRANSPARENT );
527 ::SetROP2( pData->mhDC, R2_COPYPEN );
530 // -----------------------------------------------------------------------
532 void ImplSalDeInitGraphics( WinSalGraphics* pData )
534 // clear clip region
535 SelectClipRgn( pData->mhDC, 0 );
536 // select default objects
537 if ( pData->mhDefPen )
538 SelectPen( pData->mhDC, pData->mhDefPen );
539 if ( pData->mhDefBrush )
540 SelectBrush( pData->mhDC, pData->mhDefBrush );
541 if ( pData->mhDefFont )
542 SelectFont( pData->mhDC, pData->mhDefFont );
545 // =======================================================================
547 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
549 SalData* pSalData = GetSalData();
550 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
552 if( !pC->mhDC )
554 HDC hDC = GetDC( 0 );
556 // create new DC sith DefaultBitmap
557 pC->mhDC = CreateCompatibleDC( hDC );
559 if( pSalData->mhDitherPal )
561 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
562 RealizePalette( pC->mhDC );
565 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
566 pC->mhDefBmp = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
568 ReleaseDC( 0, hDC );
571 if ( hBmp )
572 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
573 else
574 pC->mhActBmp = 0;
576 return pC->mhDC;
579 // =======================================================================
581 void ImplReleaseCachedDC( sal_uLong nID )
583 SalData* pSalData = GetSalData();
584 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
586 if ( pC->mhActBmp )
587 SelectObject( pC->mhDC, pC->mhSelBmp );
590 // =======================================================================
592 void ImplClearHDCCache( SalData* pData )
594 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
596 HDCCache* pC = &pData->mpHDCCache[ i ];
598 if( pC->mhDC )
600 SelectObject( pC->mhDC, pC->mhDefBmp );
602 if( pC->mhDefPal )
603 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
605 DeleteDC( pC->mhDC );
606 DeleteObject( pC->mhSelBmp );
611 // =======================================================================
613 // #100127# Fill point and flag memory from array of points which
614 // might also contain bezier control points for the PolyDraw() GDI method
615 // Make sure pWinPointAry and pWinFlagAry are big enough
616 void ImplPreparePolyDraw( bool bCloseFigures,
617 sal_uLong nPoly,
618 const sal_uInt32* pPoints,
619 const SalPoint* const* pPtAry,
620 const BYTE* const* pFlgAry,
621 POINT* pWinPointAry,
622 BYTE* pWinFlagAry )
624 sal_uLong nCurrPoly;
625 for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly )
627 const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ );
628 const BYTE* pCurrFlag = *pFlgAry++;
629 const sal_uInt32 nCurrPoints = *pPoints++;
630 const bool bHaveFlagArray( pCurrFlag );
631 sal_uLong nCurrPoint;
633 if( nCurrPoints )
635 // start figure
636 *pWinPointAry++ = *pCurrPoint++;
637 *pWinFlagAry++ = PT_MOVETO;
638 ++pCurrFlag;
640 for( nCurrPoint=1; nCurrPoint<nCurrPoints; )
642 // #102067# Check existence of flag array
643 if( bHaveFlagArray &&
644 ( nCurrPoint + 2 ) < nCurrPoints )
646 BYTE P4( pCurrFlag[ 2 ] );
648 if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) &&
649 ( POLY_CONTROL == pCurrFlag[ 1 ] ) &&
650 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
652 // control point one
653 *pWinPointAry++ = *pCurrPoint++;
654 *pWinFlagAry++ = PT_BEZIERTO;
656 // control point two
657 *pWinPointAry++ = *pCurrPoint++;
658 *pWinFlagAry++ = PT_BEZIERTO;
660 // end point
661 *pWinPointAry++ = *pCurrPoint++;
662 *pWinFlagAry++ = PT_BEZIERTO;
664 nCurrPoint += 3;
665 pCurrFlag += 3;
666 continue;
670 // regular line point
671 *pWinPointAry++ = *pCurrPoint++;
672 *pWinFlagAry++ = PT_LINETO;
673 ++pCurrFlag;
674 ++nCurrPoint;
677 // end figure?
678 if( bCloseFigures )
679 pWinFlagAry[-1] |= PT_CLOSEFIGURE;
684 // =======================================================================
686 // #100127# draw an array of points which might also contain bezier control points
687 void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
689 if( nPoints )
691 sal_uInt16 i;
692 // TODO: profile whether the following options are faster:
693 // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
694 // b) convert our flag array to window's and use PolyDraw
696 MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL );
697 ++pPtAry; ++pFlgAry;
699 for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry )
701 if( *pFlgAry != POLY_CONTROL )
703 LineTo( hdc, pPtAry->mnX, pPtAry->mnY );
705 else if( nPoints - i > 2 )
707 PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 );
708 i += 2; pPtAry += 2; pFlgAry += 2;
714 // =======================================================================
716 WinSalGraphics::WinSalGraphics()
718 for( int i = 0; i < MAX_FALLBACK; ++i )
720 mhFonts[ i ] = 0;
721 mpWinFontData[ i ] = NULL;
722 mpWinFontEntry[ i ] = NULL;
723 mfFontScale[ i ] = 1.0;
726 mfCurrentFontScale = 1.0;
728 mhDC = 0;
729 mhPen = 0;
730 mhBrush = 0;
731 mhRegion = 0;
732 mhDefPen = 0;
733 mhDefBrush = 0;
734 mhDefFont = 0;
735 mhDefPal = 0;
736 mpStdClipRgnData = NULL;
737 mpLogFont = NULL;
738 mpFontCharSets = NULL;
739 mpFontAttrCache = NULL;
740 mnFontCharSetCount = 0;
741 mpFontKernPairs = NULL;
742 mnFontKernPairCount = 0;
743 mbFontKernInit = FALSE;
744 mbXORMode = FALSE;
745 mnPenWidth = GSL_PEN_WIDTH;
748 // -----------------------------------------------------------------------
750 WinSalGraphics::~WinSalGraphics()
752 // free obsolete GDI objects
753 ReleaseFonts();
755 if ( mhPen )
757 if ( !mbStockPen )
758 DeletePen( mhPen );
760 if ( mhBrush )
762 if ( !mbStockBrush )
763 DeleteBrush( mhBrush );
766 if ( mhRegion )
768 DeleteRegion( mhRegion );
769 mhRegion = 0;
772 // delete cache data
773 if ( mpStdClipRgnData )
774 delete [] mpStdClipRgnData;
776 delete mpLogFont;
778 delete mpFontCharSets;
780 delete mpFontKernPairs;
783 // -----------------------------------------------------------------------
785 void WinSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
787 rDPIX = GetDeviceCaps( mhDC, LOGPIXELSX );
788 rDPIY = GetDeviceCaps( mhDC, LOGPIXELSY );
790 // #111139# this fixes the symptom of div by zero on startup
791 // however, printing will fail most likely as communication with
792 // the printer seems not to work in this case
793 if( !rDPIX || !rDPIY )
794 rDPIX = rDPIY = 600;
797 // -----------------------------------------------------------------------
799 sal_uInt16 WinSalGraphics::GetBitCount() const
801 return (sal_uInt16)GetDeviceCaps( mhDC, BITSPIXEL );
804 // -----------------------------------------------------------------------
806 long WinSalGraphics::GetGraphicsWidth() const
808 if( mhWnd && IsWindow( mhWnd ) )
810 WinSalFrame* pFrame = GetWindowPtr( mhWnd );
811 if( pFrame )
813 if( pFrame->maGeometry.nWidth )
814 return pFrame->maGeometry.nWidth;
815 else
817 // TODO: perhaps not needed, maGeometry should always be up-to-date
818 RECT aRect;
819 GetClientRect( mhWnd, &aRect );
820 return aRect.right;
825 return 0;
828 // -----------------------------------------------------------------------
830 void WinSalGraphics::ResetClipRegion()
832 if ( mhRegion )
834 DeleteRegion( mhRegion );
835 mhRegion = 0;
838 SelectClipRgn( mhDC, 0 );
841 // -----------------------------------------------------------------------
843 bool WinSalGraphics::setClipRegion( const Region& i_rClip )
845 if ( mhRegion )
847 DeleteRegion( mhRegion );
848 mhRegion = 0;
851 if( i_rClip.HasPolyPolygon() )
853 // TODO: ConvertToB2DPolyPolygon actually is kind of const, just it does not advertise it in the header
854 basegfx::B2DPolyPolygon aPolyPolygon( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() );
855 const sal_uInt32 nCount(aPolyPolygon.count());
857 if( nCount )
859 std::vector< POINT > aPolyPoints;
860 aPolyPoints.reserve( 1024 );
861 std::vector< INT > aPolyCounts( nCount, 0 );
862 for(sal_uInt32 a(0); a < nCount; a++)
864 basegfx::B2DPolygon aPoly( aPolyPolygon.getB2DPolygon(a) );
865 aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 );
866 const sal_uInt32 nPoints = aPoly.count();
867 aPolyCounts[a] = nPoints;
868 for( sal_uInt32 b = 0; b < nPoints; b++ )
870 basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) );
871 POINT aPOINT;
872 aPOINT.x = (LONG)aPt.getX();
873 aPOINT.y = (LONG)aPt.getY();
874 aPolyPoints.push_back( aPOINT );
877 mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE );
880 else
882 sal_uLong nRectCount = i_rClip.GetRectCount();
884 sal_uLong nRectBufSize = sizeof(RECT)*nRectCount;
885 if ( nRectCount < SAL_CLIPRECT_COUNT )
887 if ( !mpStdClipRgnData )
888 mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
889 mpClipRgnData = mpStdClipRgnData;
891 else
892 mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
893 mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
894 mpClipRgnData->rdh.iType = RDH_RECTANGLES;
895 mpClipRgnData->rdh.nCount = nRectCount;
896 mpClipRgnData->rdh.nRgnSize = nRectBufSize;
897 RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
898 SetRectEmpty( pBoundRect );
899 RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
900 bool bFirstClipRect = true;
902 ImplRegionInfo aInfo;
903 long nX, nY, nW, nH;
904 bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
905 while( bRegionRect )
907 if ( nW && nH )
909 long nRight = nX + nW;
910 long nBottom = nY + nH;
912 if ( bFirstClipRect )
914 pBoundRect->left = nX;
915 pBoundRect->top = nY;
916 pBoundRect->right = nRight;
917 pBoundRect->bottom = nBottom;
918 bFirstClipRect = false;
920 else
922 if ( nX < pBoundRect->left )
923 pBoundRect->left = (int)nX;
925 if ( nY < pBoundRect->top )
926 pBoundRect->top = (int)nY;
928 if ( nRight > pBoundRect->right )
929 pBoundRect->right = (int)nRight;
931 if ( nBottom > pBoundRect->bottom )
932 pBoundRect->bottom = (int)nBottom;
935 pNextClipRect->left = (int)nX;
936 pNextClipRect->top = (int)nY;
937 pNextClipRect->right = (int)nRight;
938 pNextClipRect->bottom = (int)nBottom;
939 pNextClipRect++;
941 else
943 mpClipRgnData->rdh.nCount--;
944 mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
946 bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
948 // create clip region from ClipRgnData
949 if ( mpClipRgnData->rdh.nCount == 1 )
951 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
952 mhRegion = CreateRectRgn( pRect->left, pRect->top,
953 pRect->right, pRect->bottom );
955 else if( mpClipRgnData->rdh.nCount > 1 )
957 sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
958 mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
960 // if ExtCreateRegion(...) is not supported
961 if( !mhRegion )
963 RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData;
965 if( pHeader->nCount )
967 RECT* pRect = (RECT*) mpClipRgnData->Buffer;
968 mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
969 pRect++;
971 for( sal_uLong n = 1; n < pHeader->nCount; n++, pRect++ )
973 HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
974 CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR );
975 DeleteRegion( hRgn );
980 if ( mpClipRgnData != mpStdClipRgnData )
981 delete [] mpClipRgnData;
985 if( mhRegion )
986 SelectClipRgn( mhDC, mhRegion );
987 return mhRegion != 0;
990 // -----------------------------------------------------------------------
992 void WinSalGraphics::SetLineColor()
994 // create and select new pen
995 HPEN hNewPen = GetStockPen( NULL_PEN );
996 HPEN hOldPen = SelectPen( mhDC, hNewPen );
998 // destroy or save old pen
999 if ( mhPen )
1001 if ( !mbStockPen )
1002 DeletePen( mhPen );
1004 else
1005 mhDefPen = hOldPen;
1007 // set new data
1008 mhPen = hNewPen;
1009 mbPen = FALSE;
1010 mbStockPen = TRUE;
1013 // -----------------------------------------------------------------------
1015 void WinSalGraphics::SetLineColor( SalColor nSalColor )
1017 maLineColor = nSalColor;
1018 COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
1019 SALCOLOR_GREEN( nSalColor ),
1020 SALCOLOR_BLUE( nSalColor ) );
1021 HPEN hNewPen = 0;
1022 sal_Bool bStockPen = FALSE;
1024 // search for stock pen (only screen, because printer have problems,
1025 // when we use stock objects)
1026 if ( !mbPrinter )
1028 SalData* pSalData = GetSalData();
1029 for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ )
1031 if ( nPenColor == pSalData->maStockPenColorAry[i] )
1033 hNewPen = pSalData->mhStockPenAry[i];
1034 bStockPen = TRUE;
1035 break;
1040 // create new pen
1041 if ( !hNewPen )
1043 if ( !mbPrinter )
1045 if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
1046 nPenColor = PALRGB_TO_RGB( nPenColor );
1049 hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor );
1050 bStockPen = FALSE;
1053 // select new pen
1054 HPEN hOldPen = SelectPen( mhDC, hNewPen );
1056 // destroy or save old pen
1057 if ( mhPen )
1059 if ( !mbStockPen )
1060 DeletePen( mhPen );
1062 else
1063 mhDefPen = hOldPen;
1065 // set new data
1066 mnPenColor = nPenColor;
1067 mhPen = hNewPen;
1068 mbPen = TRUE;
1069 mbStockPen = bStockPen;
1072 // -----------------------------------------------------------------------
1074 void WinSalGraphics::SetFillColor()
1076 // create and select new brush
1077 HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
1078 HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
1080 // destroy or save old brush
1081 if ( mhBrush )
1083 if ( !mbStockBrush )
1084 DeleteBrush( mhBrush );
1086 else
1087 mhDefBrush = hOldBrush;
1089 // set new data
1090 mhBrush = hNewBrush;
1091 mbBrush = FALSE;
1092 mbStockBrush = TRUE;
1095 // -----------------------------------------------------------------------
1097 void WinSalGraphics::SetFillColor( SalColor nSalColor )
1099 maFillColor = nSalColor;
1100 SalData* pSalData = GetSalData();
1101 BYTE nRed = SALCOLOR_RED( nSalColor );
1102 BYTE nGreen = SALCOLOR_GREEN( nSalColor );
1103 BYTE nBlue = SALCOLOR_BLUE( nSalColor );
1104 COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue );
1105 HBRUSH hNewBrush = 0;
1106 sal_Bool bStockBrush = FALSE;
1108 // search for stock brush (only screen, because printer have problems,
1109 // when we use stock objects)
1110 if ( !mbPrinter )
1112 for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ )
1114 if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] )
1116 hNewBrush = pSalData->mhStockBrushAry[i];
1117 bStockBrush = TRUE;
1118 break;
1123 // create new brush
1124 if ( !hNewBrush )
1126 if ( mbPrinter || !pSalData->mhDitherDIB )
1127 hNewBrush = CreateSolidBrush( nBrushColor );
1128 else
1130 if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount )
1132 BYTE* pTmp = pSalData->mpDitherDIBData;
1133 long* pDitherDiff = pSalData->mpDitherDiff;
1134 BYTE* pDitherLow = pSalData->mpDitherLow;
1135 BYTE* pDitherHigh = pSalData->mpDitherHigh;
1137 for( long nY = 0L; nY < 8L; nY++ )
1139 for( long nX = 0L; nX < 8L; nX++ )
1141 const long nThres = aOrdDither16Bit[ nY ][ nX ];
1142 *pTmp++ = DMAP( nBlue, nThres );
1143 *pTmp++ = DMAP( nGreen, nThres );
1144 *pTmp++ = DMAP( nRed, nThres );
1148 hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS );
1150 else if ( ImplIsSysColorEntry( nSalColor ) )
1152 nBrushColor = PALRGB_TO_RGB( nBrushColor );
1153 hNewBrush = CreateSolidBrush( nBrushColor );
1155 else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) )
1156 hNewBrush = CreateSolidBrush( nBrushColor );
1157 else
1159 BYTE* pTmp = pSalData->mpDitherDIBData;
1160 long* pDitherDiff = pSalData->mpDitherDiff;
1161 BYTE* pDitherLow = pSalData->mpDitherLow;
1162 BYTE* pDitherHigh = pSalData->mpDitherHigh;
1164 for ( long nY = 0L; nY < 8L; nY++ )
1166 for ( long nX = 0L; nX < 8L; nX++ )
1168 const long nThres = aOrdDither8Bit[ nY ][ nX ];
1169 *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36;
1170 pTmp++;
1174 hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
1178 bStockBrush = FALSE;
1181 // select new brush
1182 HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
1184 // destroy or save old brush
1185 if ( mhBrush )
1187 if ( !mbStockBrush )
1188 DeleteBrush( mhBrush );
1190 else
1191 mhDefBrush = hOldBrush;
1193 // set new data
1194 mnBrushColor = nBrushColor;
1195 mhBrush = hNewBrush;
1196 mbBrush = TRUE;
1197 mbStockBrush = bStockBrush;
1200 // -----------------------------------------------------------------------
1202 void WinSalGraphics::SetXORMode( bool bSet, bool )
1204 mbXORMode = bSet;
1205 ::SetROP2( mhDC, bSet ? R2_XORPEN : R2_COPYPEN );
1208 // -----------------------------------------------------------------------
1210 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
1212 SetLineColor( ImplGetROPSalColor( nROPColor ) );
1215 // -----------------------------------------------------------------------
1217 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
1219 SetFillColor( ImplGetROPSalColor( nROPColor ) );
1222 // -----------------------------------------------------------------------
1224 void WinSalGraphics::drawPixel( long nX, long nY )
1226 if ( mbXORMode )
1228 HBRUSH hBrush = CreateSolidBrush( mnPenColor );
1229 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1230 PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1231 SelectBrush( mhDC, hOldBrush );
1232 DeleteBrush( hBrush );
1234 else
1235 SetPixel( mhDC, (int)nX, (int)nY, mnPenColor );
1238 // -----------------------------------------------------------------------
1240 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
1242 COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1243 SALCOLOR_GREEN( nSalColor ),
1244 SALCOLOR_BLUE( nSalColor ) );
1246 if ( !mbPrinter &&
1247 GetSalData()->mhDitherPal &&
1248 ImplIsSysColorEntry( nSalColor ) )
1249 nCol = PALRGB_TO_RGB( nCol );
1251 if ( mbXORMode )
1253 HBRUSH hBrush = CreateSolidBrush( nCol );
1254 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1255 PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
1256 SelectBrush( mhDC, hOldBrush );
1257 DeleteBrush( hBrush );
1259 else
1260 ::SetPixel( mhDC, (int)nX, (int)nY, nCol );
1263 // -----------------------------------------------------------------------
1265 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
1267 MoveToEx( mhDC, (int)nX1, (int)nY1, NULL );
1269 // we must paint the endpoint
1270 int bPaintEnd = TRUE;
1271 if ( nX1 == nX2 )
1273 bPaintEnd = FALSE;
1274 if ( nY1 <= nY2 )
1275 nY2++;
1276 else
1277 nY2--;
1279 if ( nY1 == nY2 )
1281 bPaintEnd = FALSE;
1282 if ( nX1 <= nX2 )
1283 nX2++;
1284 else
1285 nX2--;
1288 LineTo( mhDC, (int)nX2, (int)nY2 );
1290 if ( bPaintEnd && !mbPrinter )
1292 if ( mbXORMode )
1294 HBRUSH hBrush = CreateSolidBrush( mnPenColor );
1295 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1296 PatBlt( mhDC, (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
1297 SelectBrush( mhDC, hOldBrush );
1298 DeleteBrush( hBrush );
1300 else
1301 SetPixel( mhDC, (int)nX2, (int)nY2, mnPenColor );
1305 // -----------------------------------------------------------------------
1307 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
1309 if ( !mbPen )
1311 if ( !mbPrinter )
1313 PatBlt( mhDC, (int)nX, (int)nY, (int)nWidth, (int)nHeight,
1314 mbXORMode ? PATINVERT : PATCOPY );
1316 else
1318 RECT aWinRect;
1319 aWinRect.left = nX;
1320 aWinRect.top = nY;
1321 aWinRect.right = nX+nWidth;
1322 aWinRect.bottom = nY+nHeight;
1323 ::FillRect( mhDC, &aWinRect, mhBrush );
1326 else
1327 WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
1330 // -----------------------------------------------------------------------
1332 void WinSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry )
1334 // for NT, we can handover the array directly
1335 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1336 "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
1338 POINT* pWinPtAry = (POINT*)pPtAry;
1340 // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN)
1341 // we must paint the endpoint for last line
1342 BOOL bPaintEnd = TRUE;
1343 if ( pWinPtAry[nPoints-2].x == pWinPtAry[nPoints-1].x )
1345 bPaintEnd = FALSE;
1346 if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y )
1347 pWinPtAry[nPoints-1].y++;
1348 else
1349 pWinPtAry[nPoints-1].y--;
1351 if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y )
1353 bPaintEnd = FALSE;
1354 if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x )
1355 pWinPtAry[nPoints-1].x++;
1356 else
1357 pWinPtAry[nPoints-1].x--;
1360 // for Windows 95 and its maximum number of points
1361 if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1362 Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
1364 if ( bPaintEnd && !mbPrinter )
1366 if ( mbXORMode )
1368 HBRUSH hBrush = CreateSolidBrush( mnPenColor );
1369 HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
1370 PatBlt( mhDC, (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), (int)1, (int)1, PATINVERT );
1371 SelectBrush( mhDC, hOldBrush );
1372 DeleteBrush( hBrush );
1374 else
1375 SetPixel( mhDC, (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), mnPenColor );
1379 // -----------------------------------------------------------------------
1381 void WinSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
1383 // for NT, we can handover the array directly
1384 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1385 "WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
1387 POINT* pWinPtAry = (POINT*)pPtAry;
1388 // for Windows 95 and its maximum number of points
1389 if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
1390 WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
1393 // -----------------------------------------------------------------------
1395 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1396 PCONSTSALPOINT* pPtAry )
1398 UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF];
1399 UINT* pWinPointAry;
1400 UINT nPolyPolyPoints = 0;
1401 UINT nPoints;
1402 UINT i;
1404 if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
1405 pWinPointAry = aWinPointAry;
1406 else
1407 pWinPointAry = new UINT[nPoly];
1409 for ( i = 0; i < (UINT)nPoly; i++ )
1411 nPoints = (UINT)pPoints[i]+1;
1412 pWinPointAry[i] = nPoints;
1413 nPolyPolyPoints += nPoints;
1416 POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF];
1417 POINT* pWinPointAryAry;
1418 if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF )
1419 pWinPointAryAry = aWinPointAryAry;
1420 else
1421 pWinPointAryAry = new POINT[nPolyPolyPoints];
1422 // for NT, we can handover the array directly
1423 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1424 "WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" );
1425 const SalPoint* pPolyAry;
1426 UINT n = 0;
1427 for ( i = 0; i < (UINT)nPoly; i++ )
1429 nPoints = pWinPointAry[i];
1430 pPolyAry = pPtAry[i];
1431 memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) );
1432 pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n];
1433 n += nPoints;
1436 if ( !WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
1437 (nPolyPolyPoints > MAX_64KSALPOINTS) )
1439 nPolyPolyPoints = 0;
1440 nPoly = 0;
1443 nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
1444 nPoly++;
1446 while ( nPolyPolyPoints < MAX_64KSALPOINTS );
1447 nPoly--;
1448 if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
1449 pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
1450 if ( nPoly == 1 )
1451 WIN_Polygon( mhDC, pWinPointAryAry, *pWinPointAry );
1452 else
1453 WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, nPoly );
1456 if ( pWinPointAry != aWinPointAry )
1457 delete [] pWinPointAry;
1458 if ( pWinPointAryAry != aWinPointAryAry )
1459 delete [] pWinPointAryAry;
1462 // -----------------------------------------------------------------------
1464 #define SAL_POLY_STACKBUF 32
1466 // -----------------------------------------------------------------------
1468 sal_Bool WinSalGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1470 #ifdef USE_GDI_BEZIERS
1471 // for NT, we can handover the array directly
1472 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1473 "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
1475 ImplRenderPath( mhDC, nPoints, pPtAry, pFlgAry );
1477 return sal_True;
1478 #else
1479 return sal_False;
1480 #endif
1483 // -----------------------------------------------------------------------
1485 sal_Bool WinSalGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
1487 #ifdef USE_GDI_BEZIERS
1488 // for NT, we can handover the array directly
1489 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1490 "WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" );
1492 POINT aStackAry1[SAL_POLY_STACKBUF];
1493 BYTE aStackAry2[SAL_POLY_STACKBUF];
1494 POINT* pWinPointAry;
1495 BYTE* pWinFlagAry;
1496 if( nPoints > SAL_POLY_STACKBUF )
1498 pWinPointAry = new POINT[ nPoints ];
1499 pWinFlagAry = new BYTE[ nPoints ];
1501 else
1503 pWinPointAry = aStackAry1;
1504 pWinFlagAry = aStackAry2;
1507 sal_uInt32 nPoints_i32(nPoints);
1508 ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
1510 sal_Bool bRet( sal_False );
1512 if( BeginPath( mhDC ) )
1514 PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nPoints);
1516 if( EndPath( mhDC ) )
1518 if( StrokeAndFillPath( mhDC ) )
1519 bRet = sal_True;
1523 if( pWinPointAry != aStackAry1 )
1525 delete [] pWinPointAry;
1526 delete [] pWinFlagAry;
1529 return bRet;
1530 #else
1531 return sal_False;
1532 #endif
1535 // -----------------------------------------------------------------------
1537 sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
1538 const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
1540 #ifdef USE_GDI_BEZIERS
1541 // for NT, we can handover the array directly
1542 DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
1543 "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
1545 sal_uLong nCurrPoly, nTotalPoints;
1546 const sal_uInt32* pCurrPoints = pPoints;
1547 for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
1548 nTotalPoints += *pCurrPoints++;
1550 POINT aStackAry1[SAL_POLY_STACKBUF];
1551 BYTE aStackAry2[SAL_POLY_STACKBUF];
1552 POINT* pWinPointAry;
1553 BYTE* pWinFlagAry;
1554 if( nTotalPoints > SAL_POLY_STACKBUF )
1556 pWinPointAry = new POINT[ nTotalPoints ];
1557 pWinFlagAry = new BYTE[ nTotalPoints ];
1559 else
1561 pWinPointAry = aStackAry1;
1562 pWinFlagAry = aStackAry2;
1565 ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
1567 sal_Bool bRet( sal_False );
1569 if( BeginPath( mhDC ) )
1571 PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nTotalPoints);
1573 if( EndPath( mhDC ) )
1575 if( StrokeAndFillPath( mhDC ) )
1576 bRet = sal_True;
1580 if( pWinPointAry != aStackAry1 )
1582 delete [] pWinPointAry;
1583 delete [] pWinFlagAry;
1586 return bRet;
1587 #else
1588 return sal_False;
1589 #endif
1592 // -----------------------------------------------------------------------
1594 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
1596 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize )
1598 while ( nComp-- >= nSize )
1600 sal_uLong i;
1601 for ( i = 0; i < nSize; i++ )
1603 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
1604 break;
1606 if ( i == nSize )
1607 return pSource;
1608 pSource++;
1610 return NULL;
1613 static sal_Bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
1615 sal_Bool bRetValue = FALSE;
1616 BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
1617 if ( pDest )
1619 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
1620 pDest += 14;
1622 int nSizeLeft = nSize - ( pDest - pSource );
1623 if ( nSizeLeft > 100 )
1624 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
1626 int i;
1627 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
1629 int nDivision = 1;
1630 sal_Bool bDivision = FALSE;
1631 sal_Bool bNegative = FALSE;
1632 sal_Bool bValid = TRUE;
1634 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
1635 BYTE nByte = *pDest;
1636 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
1638 switch ( nByte )
1640 case '.' :
1641 if ( bDivision )
1642 bValid = FALSE;
1643 else
1644 bDivision = TRUE;
1645 break;
1646 case '-' :
1647 bNegative = TRUE;
1648 break;
1649 default :
1650 if ( ( nByte < '0' ) || ( nByte > '9' ) )
1651 nSizeLeft = 1; // error parsing the bounding box values
1652 else if ( bValid )
1654 if ( bDivision )
1655 nDivision*=10;
1656 nNumb[i] *= 10;
1657 nNumb[i] += nByte - '0';
1659 break;
1661 nSizeLeft--;
1662 nByte = *(++pDest);
1664 if ( bNegative )
1665 nNumb[i] = -nNumb[i];
1666 if ( bDivision && ( nDivision != 1 ) )
1667 nNumb[i] /= nDivision;
1669 if ( i == 4 )
1670 bRetValue = TRUE;
1672 return bRetValue;
1675 sal_Bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
1677 sal_Bool bRetValue = FALSE;
1679 if ( mbPrinter )
1681 int nEscape = POSTSCRIPT_PASSTHROUGH;
1683 if ( Escape( mhDC, QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
1685 double nBoundingBox[4];
1687 if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
1689 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1691 // reserve place for a sal_uInt16
1692 aBuf.append( "aa" );
1694 // #107797# Write out EPS encapsulation header
1695 // ----------------------------------------------------------------------------------
1697 // directly taken from the PLRM 3.0, p. 726. Note:
1698 // this will definitely cause problems when
1699 // recursively creating and embedding PostScript files
1700 // in OOo, since we use statically-named variables
1701 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1702 // op_count_salWin). Currently, I have no idea on how to
1703 // work around that, except from scanning and
1704 // interpreting the EPS for unused identifiers.
1706 // append the real text
1707 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1708 "/dict_count_salWin countdictstack def\n"
1709 "/op_count_salWin count 1 sub def\n"
1710 "userdict begin\n"
1711 "/showpage {} def\n"
1712 "0 setgray 0 setlinecap\n"
1713 "1 setlinewidth 0 setlinejoin\n"
1714 "10 setmiterlimit [] 0 setdash newpath\n"
1715 "/languagelevel where\n"
1716 "{\n"
1717 " pop languagelevel\n"
1718 " 1 ne\n"
1719 " {\n"
1720 " false setstrokeadjust false setoverprint\n"
1721 " } if\n"
1722 "} if\n\n" );
1725 // #i10737# Apply clipping manually
1726 // ----------------------------------------------------------------------------------
1728 // Windows seems to ignore any clipping at the HDC,
1729 // when followed by a POSTSCRIPT_PASSTHROUGH
1731 // Check whether we've got a clipping, consisting of
1732 // exactly one rect (other cases should be, but aren't
1733 // handled currently)
1735 // TODO: Handle more than one rectangle here (take
1736 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1737 // characters!)
1738 if ( mhRegion != 0 &&
1739 mpStdClipRgnData != NULL &&
1740 mpClipRgnData == mpStdClipRgnData &&
1741 mpClipRgnData->rdh.nCount == 1 )
1743 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1745 aBuf.append( "\nnewpath\n" );
1746 aBuf.append( pRect->left );
1747 aBuf.append( " " );
1748 aBuf.append( pRect->top );
1749 aBuf.append( " moveto\n" );
1750 aBuf.append( pRect->right );
1751 aBuf.append( " " );
1752 aBuf.append( pRect->top );
1753 aBuf.append( " lineto\n" );
1754 aBuf.append( pRect->right );
1755 aBuf.append( " " );
1756 aBuf.append( pRect->bottom );
1757 aBuf.append( " lineto\n" );
1758 aBuf.append( pRect->left );
1759 aBuf.append( " " );
1760 aBuf.append( pRect->bottom );
1761 aBuf.append( " lineto\n"
1762 "closepath\n"
1763 "clip\n"
1764 "newpath\n" );
1767 // #107797# Write out buffer
1768 // ----------------------------------------------------------------------------------
1769 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1770 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1773 // #107797# Write out EPS transformation code
1774 // ----------------------------------------------------------------------------------
1775 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1776 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1777 // reserve a sal_uInt16 again
1778 aBuf.setLength( 2 );
1779 aBuf.append( "\n\n[" );
1780 aBuf.append( dM11 );
1781 aBuf.append( " 0 0 " );
1782 aBuf.append( dM22 );
1783 aBuf.append( ' ' );
1784 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1785 aBuf.append( ' ' );
1786 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1787 aBuf.append( "] concat\n"
1788 "%%BeginDocument:\n" );
1789 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1790 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1793 // #107797# Write out actual EPS content
1794 // ----------------------------------------------------------------------------------
1795 sal_uLong nToDo = nSize;
1796 sal_uLong nDoNow;
1797 while ( nToDo )
1799 nDoNow = nToDo;
1800 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1801 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1802 // the following is based on the string buffer allocation
1803 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1804 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
1805 memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
1806 sal_uLong nResult = Escape ( mhDC, nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
1807 if (!nResult )
1808 break;
1809 nToDo -= nResult;
1813 // #107797# Write out EPS encapsulation footer
1814 // ----------------------------------------------------------------------------------
1815 // reserve a sal_uInt16 again
1816 aBuf.setLength( 2 );
1817 aBuf.append( "%%EndDocument\n"
1818 "count op_count_salWin sub {pop} repeat\n"
1819 "countdictstack dict_count_salWin sub {end} repeat\n"
1820 "b4_Inc_state_salWin restore\n\n" );
1821 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1822 Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1823 bRetValue = TRUE;
1828 return bRetValue;
1831 // -----------------------------------------------------------------------
1833 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1835 SystemGraphicsData aRes;
1836 aRes.nSize = sizeof(aRes);
1837 aRes.hDC = mhDC;
1838 return aRes;
1841 // -----------------------------------------------------------------------
1843 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */