build fix
[LibreOffice.git] / vcl / win / gdi / salgdi.cxx
blob4474bd68756e33121b97adfa1ceb1b0aee25647a
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 .
20 #include <string.h>
21 #include <svsys.h>
22 #include <rtl/strbuf.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/poly.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/polygon/b2dpolypolygontools.hxx>
28 #include <win/wincomp.hxx>
29 #include <win/saldata.hxx>
30 #include <win/salgdi.h>
31 #include <win/salframe.h>
32 #include <win/salvd.h>
33 #include <basegfx/matrix/b2dhommatrixtools.hxx>
35 #include "salgdiimpl.hxx"
36 #include "gdiimpl.hxx"
37 #include "opengl/win/gdiimpl.hxx"
39 #include <vcl/opengl/OpenGLHelper.hxx>
42 #define DITHER_PAL_DELTA 51
43 #define DITHER_PAL_STEPS 6
44 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
45 #define DITHER_MAX_SYSCOLOR 16
46 #define DITHER_EXTRA_COLORS 1
48 struct SysColorEntry
50 DWORD nRGB;
51 SysColorEntry* pNext;
54 static SysColorEntry* pFirstSysColor = nullptr;
55 static SysColorEntry* pActSysColor = nullptr;
57 // Blue7
58 static PALETTEENTRY aImplExtraColor1 =
60 0, 184, 255, 0
63 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
65 { 0, 0, 0, 0 },
66 { 0, 0, 0x80, 0 },
67 { 0, 0x80, 0, 0 },
68 { 0, 0x80, 0x80, 0 },
69 { 0x80, 0, 0, 0 },
70 { 0x80, 0, 0x80, 0 },
71 { 0x80, 0x80, 0, 0 },
72 { 0x80, 0x80, 0x80, 0 },
73 { 0xC0, 0xC0, 0xC0, 0 },
74 { 0, 0, 0xFF, 0 },
75 { 0, 0xFF, 0, 0 },
76 { 0, 0xFF, 0xFF, 0 },
77 { 0xFF, 0, 0, 0 },
78 { 0xFF, 0, 0xFF, 0 },
79 { 0xFF, 0xFF, 0, 0 },
80 { 0xFF, 0xFF, 0xFF, 0 }
83 // we must create pens with 1-pixel width; otherwise the S3-graphics card
84 // map has many paint problems when drawing polygons/polyLines and a
85 // complex is set
86 #define GSL_PEN_WIDTH 1
88 void ImplInitSalGDI()
90 SalData* pSalData = GetSalData();
92 pSalData->mbResourcesAlreadyFreed = false;
94 // init stock brushes
95 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
96 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
97 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
98 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
99 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
100 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
101 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
102 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
103 pSalData->mnStockPenCount = 4;
105 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
106 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
107 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
108 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
109 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
110 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
111 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
112 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
113 pSalData->mnStockBrushCount = 4;
115 // initialize cache of device contexts
116 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
117 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
119 // initialize temporary font list
120 pSalData->mpTempFontItem = nullptr;
122 // support palettes for 256 color displays
123 HDC hDC = GetDC( nullptr );
124 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
125 int nPlanes = GetDeviceCaps( hDC, PLANES );
126 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
127 int nBitCount = nBitsPixel * nPlanes;
129 if ( (nBitCount > 8) && (nBitCount < 24) )
131 // test if we have to dither
132 HDC hMemDC = ::CreateCompatibleDC( hDC );
133 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
134 HBITMAP hBmpOld = static_cast<HBITMAP>(::SelectObject( hMemDC, hMemBmp ));
135 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
136 HBRUSH hBrushOld = static_cast<HBRUSH>(::SelectObject( hMemDC, hMemBrush ));
137 bool bDither16 = TRUE;
139 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
140 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
142 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
143 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
144 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
145 bDither16 = FALSE;
147 ::SelectObject( hMemDC, hBrushOld );
148 ::DeleteObject( hMemBrush );
149 ::SelectObject( hMemDC, hBmpOld );
150 ::DeleteObject( hMemBmp );
151 ::DeleteDC( hMemDC );
153 if( bDither16 )
155 // create DIBPattern for 16Bit dithering
156 long n;
158 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
159 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
160 pSalData->mpDitherDiff = new long[ 256 ];
161 pSalData->mpDitherLow = new BYTE[ 256 ];
162 pSalData->mpDitherHigh = new BYTE[ 256 ];
163 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
164 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
166 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
168 pBIH->biSize = sizeof( BITMAPINFOHEADER );
169 pBIH->biWidth = 8;
170 pBIH->biHeight = 8;
171 pBIH->biPlanes = 1;
172 pBIH->biBitCount = 24;
174 for( n = 0; n < 256; n++ )
175 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
177 for( n = 0; n < 256; n++ )
178 pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
180 for( n = 0; n < 256; n++ )
181 pSalData->mpDitherHigh[ n ] = (BYTE) std::min( pSalData->mpDitherLow[ n ] + 8, 255 );
184 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
186 BYTE nRed, nGreen, nBlue;
187 BYTE nR, nG, nB;
188 PALETTEENTRY* pPalEntry;
189 LOGPALETTE* pLogPal;
190 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
191 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
193 // create logical palette
194 pLogPal = reinterpret_cast<LOGPALETTE*>(new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ]);
195 pLogPal->palVersion = 0x0300;
196 pLogPal->palNumEntries = (sal_uInt16) nTotalCount;
197 pPalEntry = pLogPal->palPalEntry;
199 // Standard colors
200 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
201 pPalEntry += DITHER_MAX_SYSCOLOR;
203 // own palette (6/6/6)
204 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
206 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
208 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
210 pPalEntry->peRed = nRed;
211 pPalEntry->peGreen = nGreen;
212 pPalEntry->peBlue = nBlue;
213 pPalEntry->peFlags = 0;
214 pPalEntry++;
219 // insert special 'Blue' as standard drawing color
220 *pPalEntry++ = aImplExtraColor1;
222 // create palette
223 pSalData->mhDitherPal = CreatePalette( pLogPal );
224 delete[] reinterpret_cast<char*>(pLogPal);
226 if( pSalData->mhDitherPal )
228 // create DIBPattern for 8Bit dithering
229 long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
230 long n;
232 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
233 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
234 pSalData->mpDitherDiff = new long[ 256 ];
235 pSalData->mpDitherLow = new BYTE[ 256 ];
236 pSalData->mpDitherHigh = new BYTE[ 256 ];
237 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
238 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
240 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
241 short* pColors = reinterpret_cast<short*>( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
243 pBIH->biSize = sizeof( BITMAPINFOHEADER );
244 pBIH->biWidth = 8;
245 pBIH->biHeight = 8;
246 pBIH->biPlanes = 1;
247 pBIH->biBitCount = 8;
249 for( n = 0; n < nDitherPalCount; n++ )
250 pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
252 for( n = 0; n < 256; n++ )
253 pSalData->mpDitherDiff[ n ] = n % 51L;
255 for( n = 0; n < 256; n++ )
256 pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
258 for( n = 0; n < 256; n++ )
259 pSalData->mpDitherHigh[ n ] = (BYTE)std::min( pSalData->mpDitherLow[ n ] + 1, 5 );
262 // get system color entries
263 ImplUpdateSysColorEntries();
266 ReleaseDC( nullptr, hDC );
269 void ImplFreeSalGDI()
271 SalData* pSalData = GetSalData();
273 if (pSalData->mbResourcesAlreadyFreed)
274 return;
276 // destroy stock objects
277 int i;
278 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
279 DeletePen( pSalData->mhStockPenAry[i] );
280 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
281 DeleteBrush( pSalData->mhStockBrushAry[i] );
283 // delete 50% Brush
284 if ( pSalData->mh50Brush )
286 DeleteBrush( pSalData->mh50Brush );
287 pSalData->mh50Brush = nullptr;
290 // delete 50% Bitmap
291 if ( pSalData->mh50Bmp )
293 DeleteBitmap( pSalData->mh50Bmp );
294 pSalData->mh50Bmp = nullptr;
297 ImplClearHDCCache( pSalData );
298 delete[] pSalData->mpHDCCache;
300 // delete Ditherpalette, if existing
301 if ( pSalData->mhDitherPal )
303 DeleteObject( pSalData->mhDitherPal );
304 pSalData->mhDitherPal = nullptr;
307 // delete buffers for dithering DIB patterns, if necessary
308 if ( pSalData->mhDitherDIB )
310 GlobalUnlock( pSalData->mhDitherDIB );
311 GlobalFree( pSalData->mhDitherDIB );
312 pSalData->mhDitherDIB = nullptr;
313 delete[] pSalData->mpDitherDiff;
314 delete[] pSalData->mpDitherLow;
315 delete[] pSalData->mpDitherHigh;
318 // delete SysColorList
319 SysColorEntry* pEntry = pFirstSysColor;
320 while( pEntry )
322 SysColorEntry* pTmp = pEntry->pNext;
323 delete pEntry;
324 pEntry = pTmp;
326 pFirstSysColor = nullptr;
328 // delete icon cache
329 SalIcon* pIcon = pSalData->mpFirstIcon;
330 pSalData->mpFirstIcon = nullptr;
331 while( pIcon )
333 SalIcon* pTmp = pIcon->pNext;
334 DestroyIcon( pIcon->hIcon );
335 DestroyIcon( pIcon->hSmallIcon );
336 delete pIcon;
337 pIcon = pTmp;
340 // delete temporary font list
341 ImplReleaseTempFonts( *pSalData );
343 pSalData->mbResourcesAlreadyFreed = true;
346 int ImplIsSysColorEntry( SalColor nSalColor )
348 SysColorEntry* pEntry = pFirstSysColor;
349 const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
350 SALCOLOR_GREEN( nSalColor ),
351 SALCOLOR_BLUE( nSalColor ) );
353 while ( pEntry )
355 if ( pEntry->nRGB == nTestRGB )
356 return TRUE;
357 pEntry = pEntry->pNext;
360 return FALSE;
363 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
365 // dither color?
366 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
367 return TRUE;
369 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
371 // standard palette color?
372 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
374 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
375 return TRUE;
378 // extra color?
379 if ( aImplExtraColor1.peRed == nRed &&
380 aImplExtraColor1.peGreen == nGreen &&
381 aImplExtraColor1.peBlue == nBlue )
383 return TRUE;
386 return FALSE;
389 static void ImplInsertSysColorEntry( int nSysIndex )
391 const DWORD nRGB = GetSysColor( nSysIndex );
393 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
395 if ( !pFirstSysColor )
397 pActSysColor = pFirstSysColor = new SysColorEntry;
398 pFirstSysColor->nRGB = nRGB;
399 pFirstSysColor->pNext = nullptr;
401 else
403 pActSysColor = pActSysColor->pNext = new SysColorEntry;
404 pActSysColor->nRGB = nRGB;
405 pActSysColor->pNext = nullptr;
410 void ImplUpdateSysColorEntries()
412 // delete old SysColorList
413 SysColorEntry* pEntry = pFirstSysColor;
414 while( pEntry )
416 SysColorEntry* pTmp = pEntry->pNext;
417 delete pEntry;
418 pEntry = pTmp;
420 pActSysColor = pFirstSysColor = nullptr;
422 // create new sys color list
423 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
424 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
425 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
426 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
427 ImplInsertSysColorEntry( COLOR_3DFACE );
428 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
429 ImplInsertSysColorEntry( COLOR_3DLIGHT );
430 ImplInsertSysColorEntry( COLOR_3DSHADOW );
431 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
432 ImplInsertSysColorEntry( COLOR_INFOBK );
433 ImplInsertSysColorEntry( COLOR_INFOTEXT );
434 ImplInsertSysColorEntry( COLOR_BTNTEXT );
435 ImplInsertSysColorEntry( COLOR_WINDOW );
436 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
437 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
438 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
439 ImplInsertSysColorEntry( COLOR_MENU );
440 ImplInsertSysColorEntry( COLOR_MENUTEXT );
441 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
442 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
443 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
444 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
447 void WinSalGraphics::InitGraphics()
449 // calculate the minimal line width for the printer
450 if ( isPrinter() )
452 int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
453 if ( nDPIX <= 300 )
454 mnPenWidth = 0;
455 else
456 mnPenWidth = nDPIX/300;
459 ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
460 ::SetBkMode( getHDC(), TRANSPARENT );
461 ::SetROP2( getHDC(), R2_COPYPEN );
463 mpImpl->Init();
466 void WinSalGraphics::DeInitGraphics()
468 // clear clip region
469 SelectClipRgn( getHDC(), nullptr );
470 // select default objects
471 if ( mhDefPen )
472 SelectPen( getHDC(), mhDefPen );
473 if ( mhDefBrush )
474 SelectBrush( getHDC(), mhDefBrush );
475 if ( mhDefFont )
476 SelectFont( getHDC(), mhDefFont );
478 mpImpl->DeInit();
481 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
483 SalData* pSalData = GetSalData();
484 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
486 if( !pC->mhDC )
488 HDC hDC = GetDC( nullptr );
490 // create new DC with DefaultBitmap
491 pC->mhDC = CreateCompatibleDC( hDC );
493 if( pSalData->mhDitherPal )
495 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
496 RealizePalette( pC->mhDC );
499 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
500 pC->mhDefBmp = static_cast<HBITMAP>(SelectObject( pC->mhDC, pC->mhSelBmp ));
502 ReleaseDC( nullptr, hDC );
505 if ( hBmp )
506 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
507 else
508 pC->mhActBmp = nullptr;
510 return pC->mhDC;
513 void ImplReleaseCachedDC( sal_uLong nID )
515 SalData* pSalData = GetSalData();
516 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
518 if ( pC->mhActBmp )
519 SelectObject( pC->mhDC, pC->mhSelBmp );
522 void ImplClearHDCCache( SalData* pData )
524 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
526 HDCCache* pC = &pData->mpHDCCache[ i ];
528 if( pC->mhDC )
530 SelectObject( pC->mhDC, pC->mhDefBmp );
532 if( pC->mhDefPal )
533 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
535 DeleteDC( pC->mhDC );
536 DeleteObject( pC->mhSelBmp );
541 OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height)
542 : mhBitmap(nullptr)
543 , mpData(nullptr)
544 , maRects(0, 0, width, height, x, y, width, height)
546 WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
547 mpImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
549 if (!mpImpl)
551 // we avoid the OpenGL drawing, instead we draw directly to the DC
552 mhCompatibleDC = rWinGraphics.getHDC();
553 return;
556 mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
558 // move the origin so that we always paint at 0,0 - to keep the bitmap
559 // small
560 OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
562 mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
564 mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap));
567 OpenGLCompatibleDC::~OpenGLCompatibleDC()
569 if (mpImpl)
571 SelectObject(mhCompatibleDC, mhOrigBitmap);
572 DeleteObject(mhBitmap);
573 DeleteDC(mhCompatibleDC);
577 void OpenGLCompatibleDC::fill(sal_uInt32 color)
579 if (!mpData)
580 return;
582 sal_uInt32 *p = mpData;
583 for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
584 *p++ = color;
587 OpenGLTexture* OpenGLCompatibleDC::getTexture()
589 if (!mpImpl)
590 return nullptr;
592 // turn what's in the mpData into a texture
593 return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData);
596 bool OpenGLCompatibleDC::copyToTexture(OpenGLTexture& aTexture)
598 if (!mpImpl)
599 return false;
601 return aTexture.CopyData(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
604 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
605 mhLocalDC(nullptr),
606 mbPrinter(eType == WinSalGraphics::PRINTER),
607 mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
608 mbWindow(eType == WinSalGraphics::WINDOW),
609 mbScreen(bScreen),
610 mhWnd(hWnd),
611 mfCurrentFontScale(1.0),
612 mhRegion(nullptr),
613 mhDefPen(nullptr),
614 mhDefBrush(nullptr),
615 mhDefFont(nullptr),
616 mhDefPal(nullptr),
617 mpStdClipRgnData(nullptr),
618 mbFontKernInit(false),
619 mpFontKernPairs(nullptr),
620 mnFontKernPairCount(0),
621 mnPenWidth(GSL_PEN_WIDTH)
623 if (OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter)
624 mpImpl.reset(new WinOpenGLSalGraphicsImpl(*this, pProvider));
625 else
626 mpImpl.reset(new WinSalGraphicsImpl(*this));
628 for( int i = 0; i < MAX_FALLBACK; ++i )
630 mhFonts[ i ] = nullptr;
631 mpWinFontData[ i ] = nullptr;
632 mpWinFontEntry[ i ] = nullptr;
633 mfFontScale[ i ] = 1.0;
637 WinSalGraphics::~WinSalGraphics()
639 // free obsolete GDI objects
640 ReleaseFonts();
642 if ( mhRegion )
644 DeleteRegion( mhRegion );
645 mhRegion = nullptr;
648 // delete cache data
649 delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
651 delete [] mpFontKernPairs;
654 SalGraphicsImpl* WinSalGraphics::GetImpl() const
656 return mpImpl.get();
659 bool WinSalGraphics::isPrinter() const
661 return mbPrinter;
664 bool WinSalGraphics::isVirtualDevice() const
666 return mbVirDev;
669 bool WinSalGraphics::isWindow() const
671 return mbWindow;
674 bool WinSalGraphics::isScreen() const
676 return mbScreen;
679 HWND WinSalGraphics::gethWnd()
681 return mhWnd;
684 void WinSalGraphics::setHWND(HWND hWnd)
686 mhWnd = hWnd;
689 HPALETTE WinSalGraphics::getDefPal() const
691 return mhDefPal;
694 void WinSalGraphics::setDefPal(HPALETTE hDefPal)
696 mhDefPal = hDefPal;
699 HRGN WinSalGraphics::getRegion() const
701 return mhRegion;
704 void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
706 rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
707 rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
709 // #111139# this fixes the symptom of div by zero on startup
710 // however, printing will fail most likely as communication with
711 // the printer seems not to work in this case
712 if( !rDPIX || !rDPIY )
713 rDPIX = rDPIY = 600;
716 sal_uInt16 WinSalGraphics::GetBitCount() const
718 return mpImpl->GetBitCount();
721 long WinSalGraphics::GetGraphicsWidth() const
723 return mpImpl->GetGraphicsWidth();
726 void WinSalGraphics::ResetClipRegion()
728 mpImpl->ResetClipRegion();
731 bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
733 return mpImpl->setClipRegion( i_rClip );
736 void WinSalGraphics::SetLineColor()
738 mpImpl->SetLineColor();
741 void WinSalGraphics::SetLineColor( SalColor nSalColor )
743 mpImpl->SetLineColor( nSalColor );
746 void WinSalGraphics::SetFillColor()
748 mpImpl->SetFillColor();
751 void WinSalGraphics::SetFillColor( SalColor nSalColor )
753 mpImpl->SetFillColor( nSalColor );
756 void WinSalGraphics::SetXORMode( bool bSet)
758 mpImpl->SetXORMode( bSet);
761 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
763 mpImpl->SetROPLineColor( nROPColor );
766 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
768 mpImpl->SetROPFillColor( nROPColor );
771 void WinSalGraphics::drawPixel( long nX, long nY )
773 mpImpl->drawPixel( nX, nY );
776 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
778 mpImpl->drawPixel( nX, nY, nSalColor );
781 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
783 mpImpl->drawLine( nX1, nY1, nX2, nY2 );
786 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
788 mpImpl->drawRect( nX, nY, nWidth, nHeight );
791 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, SalPoint* pPtAry )
793 mpImpl->drawPolyLine( nPoints, pPtAry );
796 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
798 mpImpl->drawPolygon( nPoints, pPtAry );
801 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
802 PCONSTSALPOINT* pPtAry )
804 mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
807 bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry )
809 return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
812 bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry )
814 return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
817 bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
818 const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry )
820 return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
823 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize )
825 while ( nComp-- >= nSize )
827 sal_uLong i;
828 for ( i = 0; i < nSize; i++ )
830 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
831 break;
833 if ( i == nSize )
834 return pSource;
835 pSource++;
837 return nullptr;
840 static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
842 bool bRetValue = FALSE;
843 BYTE* pDest = ImplSearchEntry( pSource, reinterpret_cast<BYTE const *>("%%BoundingBox:"), nSize, 14 );
844 if ( pDest )
846 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
847 pDest += 14;
849 int nSizeLeft = nSize - ( pDest - pSource );
850 if ( nSizeLeft > 100 )
851 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
853 int i;
854 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
856 int nDivision = 1;
857 bool bDivision = FALSE;
858 bool bNegative = FALSE;
859 bool bValid = TRUE;
861 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
862 BYTE nByte = *pDest;
863 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
865 switch ( nByte )
867 case '.' :
868 if ( bDivision )
869 bValid = FALSE;
870 else
871 bDivision = TRUE;
872 break;
873 case '-' :
874 bNegative = TRUE;
875 break;
876 default :
877 if ( ( nByte < '0' ) || ( nByte > '9' ) )
878 nSizeLeft = 1; // error parsing the bounding box values
879 else if ( bValid )
881 if ( bDivision )
882 nDivision*=10;
883 nNumb[i] *= 10;
884 nNumb[i] += nByte - '0';
886 break;
888 nSizeLeft--;
889 nByte = *(++pDest);
891 if ( bNegative )
892 nNumb[i] = -nNumb[i];
893 if ( bDivision && ( nDivision != 1 ) )
894 nNumb[i] /= nDivision;
896 if ( i == 4 )
897 bRetValue = TRUE;
899 return bRetValue;
902 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
904 bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
906 bool bRetValue = false;
908 if ( mbPrinter )
910 int nEscape = POSTSCRIPT_PASSTHROUGH;
912 if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), reinterpret_cast<LPSTR>(&nEscape), nullptr ) )
914 double nBoundingBox[4];
916 if ( ImplGetBoundingBox( nBoundingBox, static_cast<BYTE*>(pPtr), nSize ) )
918 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
920 // reserve place for a sal_uInt16
921 aBuf.append( "aa" );
923 // #107797# Write out EPS encapsulation header
925 // directly taken from the PLRM 3.0, p. 726. Note:
926 // this will definitely cause problems when
927 // recursively creating and embedding PostScript files
928 // in OOo, since we use statically-named variables
929 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
930 // op_count_salWin). Currently, I have no idea on how to
931 // work around that, except from scanning and
932 // interpreting the EPS for unused identifiers.
934 // append the real text
935 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
936 "/dict_count_salWin countdictstack def\n"
937 "/op_count_salWin count 1 sub def\n"
938 "userdict begin\n"
939 "/showpage {} def\n"
940 "0 setgray 0 setlinecap\n"
941 "1 setlinewidth 0 setlinejoin\n"
942 "10 setmiterlimit [] 0 setdash newpath\n"
943 "/languagelevel where\n"
944 "{\n"
945 " pop languagelevel\n"
946 " 1 ne\n"
947 " {\n"
948 " false setstrokeadjust false setoverprint\n"
949 " } if\n"
950 "} if\n\n" );
952 // #i10737# Apply clipping manually
954 // Windows seems to ignore any clipping at the HDC,
955 // when followed by a POSTSCRIPT_PASSTHROUGH
957 // Check whether we've got a clipping, consisting of
958 // exactly one rect (other cases should be, but aren't
959 // handled currently)
961 // TODO: Handle more than one rectangle here (take
962 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
963 // characters!)
964 if ( mhRegion != nullptr &&
965 mpStdClipRgnData != nullptr &&
966 mpClipRgnData == mpStdClipRgnData &&
967 mpClipRgnData->rdh.nCount == 1 )
969 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
971 aBuf.append( "\nnewpath\n" );
972 aBuf.append( pRect->left );
973 aBuf.append( " " );
974 aBuf.append( pRect->top );
975 aBuf.append( " moveto\n" );
976 aBuf.append( pRect->right );
977 aBuf.append( " " );
978 aBuf.append( pRect->top );
979 aBuf.append( " lineto\n" );
980 aBuf.append( pRect->right );
981 aBuf.append( " " );
982 aBuf.append( pRect->bottom );
983 aBuf.append( " lineto\n" );
984 aBuf.append( pRect->left );
985 aBuf.append( " " );
986 aBuf.append( pRect->bottom );
987 aBuf.append( " lineto\n"
988 "closepath\n"
989 "clip\n"
990 "newpath\n" );
993 // #107797# Write out buffer
995 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = (sal_uInt16)( aBuf.getLength() - 2 );
996 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
998 // #107797# Write out EPS transformation code
1000 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1001 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1002 // reserve a sal_uInt16 again
1003 aBuf.setLength( 2 );
1004 aBuf.append( "\n\n[" );
1005 aBuf.append( dM11 );
1006 aBuf.append( " 0 0 " );
1007 aBuf.append( dM22 );
1008 aBuf.append( ' ' );
1009 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1010 aBuf.append( ' ' );
1011 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1012 aBuf.append( "] concat\n"
1013 "%%BeginDocument:\n" );
1014 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = (sal_uInt16)( aBuf.getLength() - 2 );
1015 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1017 // #107797# Write out actual EPS content
1019 sal_uLong nToDo = nSize;
1020 sal_uLong nDoNow;
1021 while ( nToDo )
1023 nDoNow = nToDo;
1024 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1025 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1026 // the following is based on the string buffer allocation
1027 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1028 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = (sal_uInt16)nDoNow;
1029 memcpy( const_cast<char *>(aBuf.getStr() + 2), static_cast<BYTE*>(pPtr) + nSize - nToDo, nDoNow );
1030 sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, aBuf.getStr(), nullptr );
1031 if (!nResult )
1032 break;
1033 nToDo -= nResult;
1036 // #107797# Write out EPS encapsulation footer
1038 // reserve a sal_uInt16 again
1039 aBuf.setLength( 2 );
1040 aBuf.append( "%%EndDocument\n"
1041 "count op_count_salWin sub {pop} repeat\n"
1042 "countdictstack dict_count_salWin sub {end} repeat\n"
1043 "b4_Inc_state_salWin restore\n\n" );
1044 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = (sal_uInt16)( aBuf.getLength() - 2 );
1045 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1046 bRetValue = TRUE;
1051 return bRetValue;
1054 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1056 SystemGraphicsData aRes;
1057 aRes.nSize = sizeof(aRes);
1058 aRes.hDC = getHDC();
1059 return aRes;
1062 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */