Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / vcl / win / gdi / salgdi.cxx
blobf1229eed34b257579f50aff4180a710624f22689
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/poly.hxx>
24 #include <basegfx/polygon/b2dpolygon.hxx>
25 #include <basegfx/polygon/b2dpolygontools.hxx>
26 #include <basegfx/polygon/b2dpolypolygontools.hxx>
27 #include <win/wincomp.hxx>
28 #include <win/saldata.hxx>
29 #include <win/salgdi.h>
30 #include <win/salframe.h>
31 #include <win/salvd.h>
32 #include <win/winlayout.hxx>
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>
41 #include <config_features.h>
42 #include <vcl/skia/SkiaHelper.hxx>
43 #if HAVE_FEATURE_SKIA
44 #include <skia/win/gdiimpl.hxx>
45 #endif
48 #define DITHER_PAL_DELTA 51
49 #define DITHER_PAL_STEPS 6
50 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
51 #define DITHER_MAX_SYSCOLOR 16
52 #define DITHER_EXTRA_COLORS 1
54 namespace
57 struct SysColorEntry
59 DWORD nRGB;
60 SysColorEntry* pNext;
63 SysColorEntry* pFirstSysColor = nullptr;
64 SysColorEntry* pActSysColor = nullptr;
66 void DeleteSysColorList()
68 SysColorEntry* pEntry = pFirstSysColor;
69 pActSysColor = pFirstSysColor = nullptr;
71 while( pEntry )
73 SysColorEntry* pTmp = pEntry->pNext;
74 delete pEntry;
75 pEntry = pTmp;
79 } // namespace
81 // Blue7
82 static PALETTEENTRY aImplExtraColor1 =
84 0, 184, 255, 0
87 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
89 { 0, 0, 0, 0 },
90 { 0, 0, 0x80, 0 },
91 { 0, 0x80, 0, 0 },
92 { 0, 0x80, 0x80, 0 },
93 { 0x80, 0, 0, 0 },
94 { 0x80, 0, 0x80, 0 },
95 { 0x80, 0x80, 0, 0 },
96 { 0x80, 0x80, 0x80, 0 },
97 { 0xC0, 0xC0, 0xC0, 0 },
98 { 0, 0, 0xFF, 0 },
99 { 0, 0xFF, 0, 0 },
100 { 0, 0xFF, 0xFF, 0 },
101 { 0xFF, 0, 0, 0 },
102 { 0xFF, 0, 0xFF, 0 },
103 { 0xFF, 0xFF, 0, 0 },
104 { 0xFF, 0xFF, 0xFF, 0 }
107 // we must create pens with 1-pixel width; otherwise the S3-graphics card
108 // map has many paint problems when drawing polygons/polyLines and a
109 // complex is set
110 #define GSL_PEN_WIDTH 1
112 void ImplInitSalGDI()
114 SalData* pSalData = GetSalData();
116 pSalData->mbResourcesAlreadyFreed = false;
118 // init stock brushes
119 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
120 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
121 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
122 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
123 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
124 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
125 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
126 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
127 pSalData->mnStockPenCount = 4;
129 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
130 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
131 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
132 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
133 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
134 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
135 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
136 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
137 pSalData->mnStockBrushCount = 4;
139 // initialize cache of device contexts
140 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
141 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
143 // initialize temporary font lists
144 pSalData->mpSharedTempFontItem = nullptr;
145 pSalData->mpOtherTempFontItem = nullptr;
147 // support palettes for 256 color displays
148 HDC hDC = GetDC( nullptr );
149 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
150 int nPlanes = GetDeviceCaps( hDC, PLANES );
151 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
152 int nBitCount = nBitsPixel * nPlanes;
154 if ( (nBitCount > 8) && (nBitCount < 24) )
156 // test if we have to dither
157 HDC hMemDC = ::CreateCompatibleDC( hDC );
158 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
159 HBITMAP hBmpOld = static_cast<HBITMAP>(::SelectObject( hMemDC, hMemBmp ));
160 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
161 HBRUSH hBrushOld = static_cast<HBRUSH>(::SelectObject( hMemDC, hMemBrush ));
162 bool bDither16 = true;
164 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
165 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
167 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
168 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
169 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
170 bDither16 = false;
172 ::SelectObject( hMemDC, hBrushOld );
173 ::DeleteObject( hMemBrush );
174 ::SelectObject( hMemDC, hBmpOld );
175 ::DeleteObject( hMemBmp );
176 ::DeleteDC( hMemDC );
178 if( bDither16 )
180 // create DIBPattern for 16Bit dithering
181 tools::Long n;
183 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
184 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
185 pSalData->mpDitherDiff = new tools::Long[ 256 ];
186 pSalData->mpDitherLow = new BYTE[ 256 ];
187 pSalData->mpDitherHigh = new BYTE[ 256 ];
188 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
189 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
191 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
193 pBIH->biSize = sizeof( BITMAPINFOHEADER );
194 pBIH->biWidth = 8;
195 pBIH->biHeight = 8;
196 pBIH->biPlanes = 1;
197 pBIH->biBitCount = 24;
199 for( n = 0; n < 256; n++ )
200 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
202 for( n = 0; n < 256; n++ )
203 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n & 248 );
205 for( n = 0; n < 256; n++ )
206 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 8, 255 ));
209 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
211 BYTE nRed, nGreen, nBlue;
212 BYTE nR, nG, nB;
213 PALETTEENTRY* pPalEntry;
214 LOGPALETTE* pLogPal;
215 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
216 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
218 // create logical palette
219 pLogPal = reinterpret_cast<LOGPALETTE*>(new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ]);
220 pLogPal->palVersion = 0x0300;
221 pLogPal->palNumEntries = static_cast<sal_uInt16>(nTotalCount);
222 pPalEntry = pLogPal->palPalEntry;
224 // Standard colors
225 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
226 pPalEntry += DITHER_MAX_SYSCOLOR;
228 // own palette (6/6/6)
229 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
231 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
233 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
235 pPalEntry->peRed = nRed;
236 pPalEntry->peGreen = nGreen;
237 pPalEntry->peBlue = nBlue;
238 pPalEntry->peFlags = 0;
239 pPalEntry++;
244 // insert special 'Blue' as standard drawing color
245 *pPalEntry++ = aImplExtraColor1;
247 // create palette
248 pSalData->mhDitherPal = CreatePalette( pLogPal );
249 delete[] reinterpret_cast<char*>(pLogPal);
251 if( pSalData->mhDitherPal )
253 // create DIBPattern for 8Bit dithering
254 tools::Long const nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
255 tools::Long n;
257 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
258 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
259 pSalData->mpDitherDiff = new tools::Long[ 256 ];
260 pSalData->mpDitherLow = new BYTE[ 256 ];
261 pSalData->mpDitherHigh = new BYTE[ 256 ];
262 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
263 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
265 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
266 short* pColors = reinterpret_cast<short*>( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
268 pBIH->biSize = sizeof( BITMAPINFOHEADER );
269 pBIH->biWidth = 8;
270 pBIH->biHeight = 8;
271 pBIH->biPlanes = 1;
272 pBIH->biBitCount = 8;
274 for( n = 0; n < nDitherPalCount; n++ )
275 pColors[ n ] = static_cast<short>( n + DITHER_MAX_SYSCOLOR );
277 for( n = 0; n < 256; n++ )
278 pSalData->mpDitherDiff[ n ] = n % 51;
280 for( n = 0; n < 256; n++ )
281 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n / 51 );
283 for( n = 0; n < 256; n++ )
284 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 1, 5 ));
287 // get system color entries
288 ImplUpdateSysColorEntries();
291 ReleaseDC( nullptr, hDC );
294 void ImplFreeSalGDI()
296 SalData* pSalData = GetSalData();
298 if (pSalData->mbResourcesAlreadyFreed)
299 return;
301 // destroy stock objects
302 int i;
303 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
304 DeletePen( pSalData->mhStockPenAry[i] );
305 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
306 DeleteBrush( pSalData->mhStockBrushAry[i] );
308 // delete 50% Brush
309 if ( pSalData->mh50Brush )
311 DeleteBrush( pSalData->mh50Brush );
312 pSalData->mh50Brush = nullptr;
315 // delete 50% Bitmap
316 if ( pSalData->mh50Bmp )
318 DeleteBitmap( pSalData->mh50Bmp );
319 pSalData->mh50Bmp = nullptr;
322 ImplClearHDCCache( pSalData );
323 delete[] pSalData->mpHDCCache;
325 // delete Ditherpalette, if existing
326 if ( pSalData->mhDitherPal )
328 DeleteObject( pSalData->mhDitherPal );
329 pSalData->mhDitherPal = nullptr;
332 // delete buffers for dithering DIB patterns, if necessary
333 if ( pSalData->mhDitherDIB )
335 GlobalUnlock( pSalData->mhDitherDIB );
336 GlobalFree( pSalData->mhDitherDIB );
337 pSalData->mhDitherDIB = nullptr;
338 delete[] pSalData->mpDitherDiff;
339 delete[] pSalData->mpDitherLow;
340 delete[] pSalData->mpDitherHigh;
343 DeleteSysColorList();
345 // delete icon cache
346 SalIcon* pIcon = pSalData->mpFirstIcon;
347 pSalData->mpFirstIcon = nullptr;
348 while( pIcon )
350 SalIcon* pTmp = pIcon->pNext;
351 DestroyIcon( pIcon->hIcon );
352 DestroyIcon( pIcon->hSmallIcon );
353 delete pIcon;
354 pIcon = pTmp;
357 // delete temporary font list
358 ImplReleaseTempFonts(*pSalData, true);
360 pSalData->mbResourcesAlreadyFreed = true;
363 int ImplIsSysColorEntry( Color nColor )
365 SysColorEntry* pEntry = pFirstSysColor;
366 const DWORD nTestRGB = static_cast<DWORD>(RGB( nColor.GetRed(),
367 nColor.GetGreen(),
368 nColor.GetBlue() ));
370 while ( pEntry )
372 if ( pEntry->nRGB == nTestRGB )
373 return TRUE;
374 pEntry = pEntry->pNext;
377 return FALSE;
380 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
382 // dither color?
383 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
384 return TRUE;
386 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
388 // standard palette color?
389 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
391 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
392 return TRUE;
395 // extra color?
396 if ( aImplExtraColor1.peRed == nRed &&
397 aImplExtraColor1.peGreen == nGreen &&
398 aImplExtraColor1.peBlue == nBlue )
400 return TRUE;
403 return FALSE;
406 static void ImplInsertSysColorEntry( int nSysIndex )
408 const DWORD nRGB = GetSysColor( nSysIndex );
410 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
412 if ( !pFirstSysColor )
414 pActSysColor = pFirstSysColor = new SysColorEntry;
415 pFirstSysColor->nRGB = nRGB;
416 pFirstSysColor->pNext = nullptr;
418 else
420 pActSysColor = pActSysColor->pNext = new SysColorEntry;
421 pActSysColor->nRGB = nRGB;
422 pActSysColor->pNext = nullptr;
427 void ImplUpdateSysColorEntries()
429 DeleteSysColorList();
431 // create new sys color list
432 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
433 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
434 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
435 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
436 ImplInsertSysColorEntry( COLOR_3DFACE );
437 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
438 ImplInsertSysColorEntry( COLOR_3DLIGHT );
439 ImplInsertSysColorEntry( COLOR_3DSHADOW );
440 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
441 ImplInsertSysColorEntry( COLOR_INFOBK );
442 ImplInsertSysColorEntry( COLOR_INFOTEXT );
443 ImplInsertSysColorEntry( COLOR_BTNTEXT );
444 ImplInsertSysColorEntry( COLOR_WINDOW );
445 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
446 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
447 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
448 ImplInsertSysColorEntry( COLOR_MENU );
449 ImplInsertSysColorEntry( COLOR_MENUTEXT );
450 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
451 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
452 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
453 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
456 void WinSalGraphics::InitGraphics()
458 // calculate the minimal line width for the printer
459 if ( isPrinter() )
461 int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
462 if ( nDPIX <= 300 )
463 mnPenWidth = 0;
464 else
465 mnPenWidth = nDPIX/300;
468 ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
469 ::SetBkMode( getHDC(), TRANSPARENT );
470 ::SetROP2( getHDC(), R2_COPYPEN );
472 mpImpl->Init();
475 void WinSalGraphics::DeInitGraphics()
477 // clear clip region
478 SelectClipRgn( getHDC(), nullptr );
479 // select default objects
480 if ( mhDefPen )
481 SelectPen( getHDC(), mhDefPen );
482 if ( mhDefBrush )
483 SelectBrush( getHDC(), mhDefBrush );
484 if ( mhDefFont )
485 SelectFont( getHDC(), mhDefFont );
487 mpImpl->DeInit();
490 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
492 SalData* pSalData = GetSalData();
493 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
495 if( !pC->mhDC )
497 HDC hDC = GetDC( nullptr );
499 // create new DC with DefaultBitmap
500 pC->mhDC = CreateCompatibleDC( hDC );
502 if( pSalData->mhDitherPal )
504 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
505 RealizePalette( pC->mhDC );
508 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
509 pC->mhDefBmp = static_cast<HBITMAP>(SelectObject( pC->mhDC, pC->mhSelBmp ));
511 ReleaseDC( nullptr, hDC );
514 if ( hBmp )
515 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
516 else
517 pC->mhActBmp = nullptr;
519 return pC->mhDC;
522 void ImplReleaseCachedDC( sal_uLong nID )
524 SalData* pSalData = GetSalData();
525 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
527 if ( pC->mhActBmp )
528 SelectObject( pC->mhDC, pC->mhSelBmp );
531 void ImplClearHDCCache( SalData* pData )
533 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
535 HDCCache* pC = &pData->mpHDCCache[ i ];
537 if( pC->mhDC )
539 SelectObject( pC->mhDC, pC->mhDefBmp );
541 if( pC->mhDefPal )
542 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
544 DeleteDC( pC->mhDC );
545 DeleteObject( pC->mhSelBmp );
550 std::unique_ptr< CompatibleDC > CompatibleDC::create(SalGraphics &rGraphics, int x, int y, int width, int height)
552 #if HAVE_FEATURE_SKIA
553 if (SkiaHelper::isVCLSkiaEnabled())
554 return std::make_unique< SkiaCompatibleDC >( rGraphics, x, y, width, height );
555 #endif
556 if (OpenGLHelper::isVCLOpenGLEnabled())
557 return std::make_unique< OpenGLCompatibleDC >( rGraphics, x, y, width, height );
558 return std::unique_ptr< CompatibleDC >( new CompatibleDC( rGraphics, x, y, width, height ));
561 CompatibleDC::CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable)
562 : mhBitmap(nullptr)
563 , mpData(nullptr)
564 , maRects(0, 0, width, height, x, y, width, height)
565 , mpImpl(nullptr)
567 WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
569 if( disable )
571 // we avoid the OpenGL drawing, instead we draw directly to the DC
572 mhCompatibleDC = rWinGraphics.getHDC();
573 return;
576 mpImpl = dynamic_cast<WinSalGraphicsImplBase*>(rWinGraphics.GetImpl());
577 assert(mpImpl != nullptr);
578 mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
580 // move the origin so that we always paint at 0,0 - to keep the bitmap
581 // small
582 OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
584 mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
586 mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap));
589 CompatibleDC::~CompatibleDC()
591 if (mpImpl)
593 SelectObject(mhCompatibleDC, mhOrigBitmap);
594 DeleteObject(mhBitmap);
595 DeleteDC(mhCompatibleDC);
599 void CompatibleDC::fill(sal_uInt32 color)
601 if (!mpData)
602 return;
604 sal_uInt32 *p = mpData;
605 for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
606 *p++ = color;
609 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
610 mhLocalDC(nullptr),
611 mbPrinter(eType == WinSalGraphics::PRINTER),
612 mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
613 mbWindow(eType == WinSalGraphics::WINDOW),
614 mbScreen(bScreen),
615 mhWnd(hWnd),
616 mhRegion(nullptr),
617 mhDefPen(nullptr),
618 mhDefBrush(nullptr),
619 mhDefFont(nullptr),
620 mhDefPal(nullptr),
621 mpStdClipRgnData(nullptr),
622 mnPenWidth(GSL_PEN_WIDTH)
624 #if HAVE_FEATURE_SKIA
625 if (SkiaHelper::isVCLSkiaEnabled() && !mbPrinter)
626 mpImpl.reset(new WinSkiaSalGraphicsImpl(*this, pProvider));
627 else
628 #endif
629 if (OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter)
630 mpImpl.reset(new WinOpenGLSalGraphicsImpl(*this, pProvider));
631 else
632 mpImpl.reset(new WinSalGraphicsImpl(*this));
635 WinSalGraphics::~WinSalGraphics()
637 // free obsolete GDI objects
638 ReleaseFonts();
640 if ( mhRegion )
642 DeleteRegion( mhRegion );
643 mhRegion = nullptr;
646 // delete cache data
647 delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
650 SalGraphicsImpl* WinSalGraphics::GetImpl() const
652 return mpImpl.get();
655 bool WinSalGraphics::isPrinter() const
657 return mbPrinter;
660 bool WinSalGraphics::isVirtualDevice() const
662 return mbVirDev;
665 bool WinSalGraphics::isWindow() const
667 return mbWindow;
670 bool WinSalGraphics::isScreen() const
672 return mbScreen;
675 HWND WinSalGraphics::gethWnd()
677 return mhWnd;
680 void WinSalGraphics::setHWND(HWND hWnd)
682 mhWnd = hWnd;
685 HPALETTE WinSalGraphics::getDefPal() const
687 return mhDefPal;
690 void WinSalGraphics::setDefPal(HPALETTE hDefPal)
692 mhDefPal = hDefPal;
695 HRGN WinSalGraphics::getRegion() const
697 return mhRegion;
700 void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
702 rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
703 rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
705 // #111139# this fixes the symptom of div by zero on startup
706 // however, printing will fail most likely as communication with
707 // the printer seems not to work in this case
708 if( !rDPIX || !rDPIY )
709 rDPIX = rDPIY = 600;
712 sal_uInt16 WinSalGraphics::GetBitCount() const
714 return mpImpl->GetBitCount();
717 tools::Long WinSalGraphics::GetGraphicsWidth() const
719 return mpImpl->GetGraphicsWidth();
722 void WinSalGraphics::Flush()
724 if(WinSalGraphicsImplBase* impl = dynamic_cast<WinSalGraphicsImplBase*>(GetImpl()))
725 impl->Flush();
728 void WinSalGraphics::ResetClipRegion()
730 mpImpl->ResetClipRegion();
733 bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
735 return mpImpl->setClipRegion( i_rClip );
738 void WinSalGraphics::SetLineColor()
740 mpImpl->SetLineColor();
743 void WinSalGraphics::SetLineColor( Color nColor )
745 mpImpl->SetLineColor( nColor );
748 void WinSalGraphics::SetFillColor()
750 mpImpl->SetFillColor();
753 void WinSalGraphics::SetFillColor( Color nColor )
755 mpImpl->SetFillColor( nColor );
758 void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
760 mpImpl->SetXORMode( bSet, bInvertOnly );
763 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
765 mpImpl->SetROPLineColor( nROPColor );
768 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
770 mpImpl->SetROPFillColor( nROPColor );
773 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY )
775 mpImpl->drawPixel( nX, nY );
778 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
780 mpImpl->drawPixel( nX, nY, nColor );
783 void WinSalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
785 mpImpl->drawLine( nX1, nY1, nX2, nY2 );
788 void WinSalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
790 mpImpl->drawRect( nX, nY, nWidth, nHeight );
793 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry )
795 mpImpl->drawPolyLine( nPoints, pPtAry );
798 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
800 mpImpl->drawPolygon( nPoints, pPtAry );
803 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
804 const Point** pPtAry )
806 mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
809 bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
811 return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
814 bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
816 return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
819 bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
820 const Point* const* pPtAry, const PolyFlags* const* pFlgAry )
822 return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
825 bool WinSalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
827 return mpImpl->drawGradient(rPoly, rGradient);
830 bool WinSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
832 return mpImpl->implDrawGradient(rPolyPolygon, rGradient);
835 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize )
837 while ( nComp-- >= nSize )
839 sal_uLong i;
840 for ( i = 0; i < nSize; i++ )
842 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
843 break;
845 if ( i == nSize )
846 return pSource;
847 pSource++;
849 return nullptr;
852 static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
854 bool bRetValue = false;
855 BYTE* pDest = ImplSearchEntry( pSource, reinterpret_cast<BYTE const *>("%%BoundingBox:"), nSize, 14 );
856 if ( pDest )
858 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
859 pDest += 14;
861 int nSizeLeft = nSize - ( pDest - pSource );
862 if ( nSizeLeft > 100 )
863 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
865 int i;
866 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
868 int nDivision = 1;
869 bool bDivision = false;
870 bool bNegative = false;
871 bool bValid = true;
873 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
874 BYTE nByte = *pDest;
875 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
877 switch ( nByte )
879 case '.' :
880 if ( bDivision )
881 bValid = false;
882 else
883 bDivision = true;
884 break;
885 case '-' :
886 bNegative = true;
887 break;
888 default :
889 if ( ( nByte < '0' ) || ( nByte > '9' ) )
890 nSizeLeft = 1; // error parsing the bounding box values
891 else if ( bValid )
893 if ( bDivision )
894 nDivision*=10;
895 nNumb[i] *= 10;
896 nNumb[i] += nByte - '0';
898 break;
900 nSizeLeft--;
901 nByte = *(++pDest);
903 if ( bNegative )
904 nNumb[i] = -nNumb[i];
905 if ( bDivision && ( nDivision != 1 ) )
906 nNumb[i] /= nDivision;
908 if ( i == 4 )
909 bRetValue = true;
911 return bRetValue;
914 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
916 bool WinSalGraphics::drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize )
918 bool bRetValue = false;
920 if ( mbPrinter )
922 int nEscape = POSTSCRIPT_PASSTHROUGH;
924 if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), reinterpret_cast<LPSTR>(&nEscape), nullptr ) )
926 double nBoundingBox[4];
928 if ( ImplGetBoundingBox( nBoundingBox, static_cast<BYTE*>(pPtr), nSize ) )
930 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
932 // reserve place for a sal_uInt16
933 aBuf.append( "aa" );
935 // #107797# Write out EPS encapsulation header
937 // directly taken from the PLRM 3.0, p. 726. Note:
938 // this will definitely cause problems when
939 // recursively creating and embedding PostScript files
940 // in OOo, since we use statically-named variables
941 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
942 // op_count_salWin). Currently, I have no idea on how to
943 // work around that, except from scanning and
944 // interpreting the EPS for unused identifiers.
946 // append the real text
947 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
948 "/dict_count_salWin countdictstack def\n"
949 "/op_count_salWin count 1 sub def\n"
950 "userdict begin\n"
951 "/showpage {} def\n"
952 "0 setgray 0 setlinecap\n"
953 "1 setlinewidth 0 setlinejoin\n"
954 "10 setmiterlimit [] 0 setdash newpath\n"
955 "/languagelevel where\n"
956 "{\n"
957 " pop languagelevel\n"
958 " 1 ne\n"
959 " {\n"
960 " false setstrokeadjust false setoverprint\n"
961 " } if\n"
962 "} if\n\n" );
964 // #i10737# Apply clipping manually
966 // Windows seems to ignore any clipping at the HDC,
967 // when followed by a POSTSCRIPT_PASSTHROUGH
969 // Check whether we've got a clipping, consisting of
970 // exactly one rect (other cases should be, but aren't
971 // handled currently)
973 // TODO: Handle more than one rectangle here (take
974 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
975 // characters!)
976 if ( mhRegion != nullptr &&
977 mpStdClipRgnData != nullptr &&
978 mpClipRgnData == mpStdClipRgnData &&
979 mpClipRgnData->rdh.nCount == 1 )
981 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
983 aBuf.append( "\nnewpath\n" );
984 aBuf.append( pRect->left );
985 aBuf.append( " " );
986 aBuf.append( pRect->top );
987 aBuf.append( " moveto\n" );
988 aBuf.append( pRect->right );
989 aBuf.append( " " );
990 aBuf.append( pRect->top );
991 aBuf.append( " lineto\n" );
992 aBuf.append( pRect->right );
993 aBuf.append( " " );
994 aBuf.append( pRect->bottom );
995 aBuf.append( " lineto\n" );
996 aBuf.append( pRect->left );
997 aBuf.append( " " );
998 aBuf.append( pRect->bottom );
999 aBuf.append( " lineto\n"
1000 "closepath\n"
1001 "clip\n"
1002 "newpath\n" );
1005 // #107797# Write out buffer
1007 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1008 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1010 // #107797# Write out EPS transformation code
1012 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1013 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1014 // reserve a sal_uInt16 again
1015 aBuf.setLength( 2 );
1016 aBuf.append( "\n\n[" );
1017 aBuf.append( dM11 );
1018 aBuf.append( " 0 0 " );
1019 aBuf.append( dM22 );
1020 aBuf.append( ' ' );
1021 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1022 aBuf.append( ' ' );
1023 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1024 aBuf.append( "] concat\n"
1025 "%%BeginDocument:\n" );
1026 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1027 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1029 // #107797# Write out actual EPS content
1031 sal_uLong nToDo = nSize;
1032 sal_uLong nDoNow;
1033 while ( nToDo )
1035 nDoNow = nToDo;
1036 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1037 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1038 // the following is based on the string buffer allocation
1039 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1040 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>(nDoNow);
1041 memcpy( const_cast<char *>(aBuf.getStr() + 2), static_cast<BYTE*>(pPtr) + nSize - nToDo, nDoNow );
1042 sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, aBuf.getStr(), nullptr );
1043 if (!nResult )
1044 break;
1045 nToDo -= nResult;
1048 // #107797# Write out EPS encapsulation footer
1050 // reserve a sal_uInt16 again
1051 aBuf.setLength( 2 );
1052 aBuf.append( "%%EndDocument\n"
1053 "count op_count_salWin sub {pop} repeat\n"
1054 "countdictstack dict_count_salWin sub {end} repeat\n"
1055 "b4_Inc_state_salWin restore\n\n" );
1056 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1057 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1058 bRetValue = true;
1063 return bRetValue;
1066 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1068 SystemGraphicsData aRes;
1069 aRes.nSize = sizeof(aRes);
1070 aRes.hDC = getHDC();
1071 return aRes;
1074 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */