calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / win / gdi / salgdi.cxx
blob48ba63e0b192669b2a6c21eeb4340c2b745d34d0
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 <comphelper/windowserrorstring.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 <win/winlayout.hxx>
34 #include <basegfx/matrix/b2dhommatrixtools.hxx>
36 #include <salgdiimpl.hxx>
37 #include "gdiimpl.hxx"
39 #include <config_features.h>
40 #include <vcl/skia/SkiaHelper.hxx>
41 #if HAVE_FEATURE_SKIA
42 #include <skia/win/gdiimpl.hxx>
43 #endif
46 #define DITHER_PAL_DELTA 51
47 #define DITHER_PAL_STEPS 6
48 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
49 #define DITHER_MAX_SYSCOLOR 16
50 #define DITHER_EXTRA_COLORS 1
52 namespace
55 struct SysColorEntry
57 DWORD nRGB;
58 SysColorEntry* pNext;
61 SysColorEntry* pFirstSysColor = nullptr;
62 SysColorEntry* pActSysColor = nullptr;
64 void DeleteSysColorList()
66 SysColorEntry* pEntry = pFirstSysColor;
67 pActSysColor = pFirstSysColor = nullptr;
69 while( pEntry )
71 SysColorEntry* pTmp = pEntry->pNext;
72 delete pEntry;
73 pEntry = pTmp;
77 } // namespace
79 // Blue7
80 static PALETTEENTRY aImplExtraColor1 =
82 0, 184, 255, 0
85 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
87 { 0, 0, 0, 0 },
88 { 0, 0, 0x80, 0 },
89 { 0, 0x80, 0, 0 },
90 { 0, 0x80, 0x80, 0 },
91 { 0x80, 0, 0, 0 },
92 { 0x80, 0, 0x80, 0 },
93 { 0x80, 0x80, 0, 0 },
94 { 0x80, 0x80, 0x80, 0 },
95 { 0xC0, 0xC0, 0xC0, 0 },
96 { 0, 0, 0xFF, 0 },
97 { 0, 0xFF, 0, 0 },
98 { 0, 0xFF, 0xFF, 0 },
99 { 0xFF, 0, 0, 0 },
100 { 0xFF, 0, 0xFF, 0 },
101 { 0xFF, 0xFF, 0, 0 },
102 { 0xFF, 0xFF, 0xFF, 0 }
105 // we must create pens with 1-pixel width; otherwise the S3-graphics card
106 // map has many paint problems when drawing polygons/polyLines and a
107 // complex is set
108 #define GSL_PEN_WIDTH 1
110 void ImplInitSalGDI()
112 SalData* pSalData = GetSalData();
114 pSalData->mbResourcesAlreadyFreed = false;
116 // init stock brushes
117 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
118 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
119 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
120 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
121 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
122 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
123 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
124 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
125 pSalData->mnStockPenCount = 4;
127 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
128 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
129 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
130 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
131 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
132 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
133 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
134 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
135 pSalData->mnStockBrushCount = 4;
137 // initialize cache of device contexts
138 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
139 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
141 // initialize temporary font lists
142 pSalData->mpSharedTempFontItem = nullptr;
143 pSalData->mpOtherTempFontItem = nullptr;
145 // support palettes for 256 color displays
146 HDC hDC = GetDC( nullptr );
147 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
148 int nPlanes = GetDeviceCaps( hDC, PLANES );
149 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
150 int nBitCount = nBitsPixel * nPlanes;
152 if ( (nBitCount > 8) && (nBitCount < 24) )
154 // test if we have to dither
155 HDC hMemDC = ::CreateCompatibleDC( hDC );
156 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
157 HBITMAP hBmpOld = static_cast<HBITMAP>(::SelectObject( hMemDC, hMemBmp ));
158 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
159 HBRUSH hBrushOld = static_cast<HBRUSH>(::SelectObject( hMemDC, hMemBrush ));
160 bool bDither16 = true;
162 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
163 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
165 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
166 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
167 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
168 bDither16 = false;
170 ::SelectObject( hMemDC, hBrushOld );
171 ::DeleteObject( hMemBrush );
172 ::SelectObject( hMemDC, hBmpOld );
173 ::DeleteObject( hMemBmp );
174 ::DeleteDC( hMemDC );
176 if( bDither16 )
178 // create DIBPattern for 16Bit dithering
179 tools::Long n;
181 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
182 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
183 pSalData->mpDitherDiff = new tools::Long[ 256 ];
184 pSalData->mpDitherLow = new BYTE[ 256 ];
185 pSalData->mpDitherHigh = new BYTE[ 256 ];
186 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
187 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
189 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
191 pBIH->biSize = sizeof( BITMAPINFOHEADER );
192 pBIH->biWidth = 8;
193 pBIH->biHeight = 8;
194 pBIH->biPlanes = 1;
195 pBIH->biBitCount = 24;
197 for( n = 0; n < 256; n++ )
198 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
200 for( n = 0; n < 256; n++ )
201 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n & 248 );
203 for( n = 0; n < 256; n++ )
204 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 8, 255 ));
207 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
209 BYTE nRed, nGreen, nBlue;
210 BYTE nR, nG, nB;
211 PALETTEENTRY* pPalEntry;
212 LOGPALETTE* pLogPal;
213 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
214 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
216 // create logical palette
217 pLogPal = reinterpret_cast<LOGPALETTE*>(new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ]);
218 pLogPal->palVersion = 0x0300;
219 pLogPal->palNumEntries = static_cast<sal_uInt16>(nTotalCount);
220 pPalEntry = pLogPal->palPalEntry;
222 // Standard colors
223 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
224 pPalEntry += DITHER_MAX_SYSCOLOR;
226 // own palette (6/6/6)
227 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
229 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
231 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
233 pPalEntry->peRed = nRed;
234 pPalEntry->peGreen = nGreen;
235 pPalEntry->peBlue = nBlue;
236 pPalEntry->peFlags = 0;
237 pPalEntry++;
242 // insert special 'Blue' as standard drawing color
243 *pPalEntry++ = aImplExtraColor1;
245 // create palette
246 pSalData->mhDitherPal = CreatePalette( pLogPal );
247 delete[] reinterpret_cast<char*>(pLogPal);
249 if( pSalData->mhDitherPal )
251 // create DIBPattern for 8Bit dithering
252 tools::Long const nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
253 tools::Long n;
255 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
256 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
257 pSalData->mpDitherDiff = new tools::Long[ 256 ];
258 pSalData->mpDitherLow = new BYTE[ 256 ];
259 pSalData->mpDitherHigh = new BYTE[ 256 ];
260 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
261 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
263 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
264 short* pColors = reinterpret_cast<short*>( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
266 pBIH->biSize = sizeof( BITMAPINFOHEADER );
267 pBIH->biWidth = 8;
268 pBIH->biHeight = 8;
269 pBIH->biPlanes = 1;
270 pBIH->biBitCount = 8;
272 for( n = 0; n < nDitherPalCount; n++ )
273 pColors[ n ] = static_cast<short>( n + DITHER_MAX_SYSCOLOR );
275 for( n = 0; n < 256; n++ )
276 pSalData->mpDitherDiff[ n ] = n % 51;
278 for( n = 0; n < 256; n++ )
279 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n / 51 );
281 for( n = 0; n < 256; n++ )
282 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 1, 5 ));
285 // get system color entries
286 ImplUpdateSysColorEntries();
289 ReleaseDC( nullptr, hDC );
292 void ImplFreeSalGDI()
294 SalData* pSalData = GetSalData();
296 if (pSalData->mbResourcesAlreadyFreed)
297 return;
299 // destroy stock objects
300 int i;
301 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
302 DeletePen( pSalData->mhStockPenAry[i] );
303 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
304 DeleteBrush( pSalData->mhStockBrushAry[i] );
306 // delete 50% Brush
307 if ( pSalData->mh50Brush )
309 DeleteBrush( pSalData->mh50Brush );
310 pSalData->mh50Brush = nullptr;
313 // delete 50% Bitmap
314 if ( pSalData->mh50Bmp )
316 DeleteBitmap( pSalData->mh50Bmp );
317 pSalData->mh50Bmp = nullptr;
320 ImplClearHDCCache( pSalData );
321 delete[] pSalData->mpHDCCache;
323 // delete Ditherpalette, if existing
324 if ( pSalData->mhDitherPal )
326 DeleteObject( pSalData->mhDitherPal );
327 pSalData->mhDitherPal = nullptr;
330 // delete buffers for dithering DIB patterns, if necessary
331 if ( pSalData->mhDitherDIB )
333 GlobalUnlock( pSalData->mhDitherDIB );
334 GlobalFree( pSalData->mhDitherDIB );
335 pSalData->mhDitherDIB = nullptr;
336 delete[] pSalData->mpDitherDiff;
337 delete[] pSalData->mpDitherLow;
338 delete[] pSalData->mpDitherHigh;
341 DeleteSysColorList();
343 // delete icon cache
344 SalIcon* pIcon = pSalData->mpFirstIcon;
345 pSalData->mpFirstIcon = nullptr;
346 while( pIcon )
348 SalIcon* pTmp = pIcon->pNext;
349 DestroyIcon( pIcon->hIcon );
350 DestroyIcon( pIcon->hSmallIcon );
351 delete pIcon;
352 pIcon = pTmp;
355 // delete temporary font list
356 ImplReleaseTempFonts(*pSalData, true);
358 pSalData->mbResourcesAlreadyFreed = true;
361 int ImplIsSysColorEntry( Color nColor )
363 SysColorEntry* pEntry = pFirstSysColor;
364 const DWORD nTestRGB = static_cast<DWORD>(RGB( nColor.GetRed(),
365 nColor.GetGreen(),
366 nColor.GetBlue() ));
368 while ( pEntry )
370 if ( pEntry->nRGB == nTestRGB )
371 return TRUE;
372 pEntry = pEntry->pNext;
375 return FALSE;
378 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
380 // dither color?
381 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
382 return TRUE;
384 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
386 // standard palette color?
387 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
389 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
390 return TRUE;
393 // extra color?
394 if ( aImplExtraColor1.peRed == nRed &&
395 aImplExtraColor1.peGreen == nGreen &&
396 aImplExtraColor1.peBlue == nBlue )
398 return TRUE;
401 return FALSE;
404 static void ImplInsertSysColorEntry( int nSysIndex )
406 const DWORD nRGB = GetSysColor( nSysIndex );
408 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
410 if ( !pFirstSysColor )
412 pActSysColor = pFirstSysColor = new SysColorEntry;
413 pFirstSysColor->nRGB = nRGB;
414 pFirstSysColor->pNext = nullptr;
416 else
418 pActSysColor = pActSysColor->pNext = new SysColorEntry;
419 pActSysColor->nRGB = nRGB;
420 pActSysColor->pNext = nullptr;
425 void ImplUpdateSysColorEntries()
427 DeleteSysColorList();
429 // create new sys color list
430 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
431 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
432 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
433 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
434 ImplInsertSysColorEntry( COLOR_3DFACE );
435 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
436 ImplInsertSysColorEntry( COLOR_3DLIGHT );
437 ImplInsertSysColorEntry( COLOR_3DSHADOW );
438 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
439 ImplInsertSysColorEntry( COLOR_INFOBK );
440 ImplInsertSysColorEntry( COLOR_INFOTEXT );
441 ImplInsertSysColorEntry( COLOR_BTNTEXT );
442 ImplInsertSysColorEntry( COLOR_WINDOW );
443 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
444 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
445 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
446 ImplInsertSysColorEntry( COLOR_MENU );
447 ImplInsertSysColorEntry( COLOR_MENUTEXT );
448 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
449 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
450 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
451 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
454 void WinSalGraphics::InitGraphics()
456 if (!getHDC())
457 return;
459 // calculate the minimal line width for the printer
460 if ( isPrinter() )
462 int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
463 if ( nDPIX <= 300 )
464 mnPenWidth = 0;
465 else
466 mnPenWidth = nDPIX/300;
469 ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
470 ::SetBkMode( getHDC(), TRANSPARENT );
471 ::SetROP2( getHDC(), R2_COPYPEN );
473 mpImpl->Init();
476 void WinSalGraphics::DeInitGraphics()
478 if (!getHDC())
479 return;
481 // clear clip region
482 SelectClipRgn( getHDC(), nullptr );
483 // select default objects
484 if ( mhDefPen )
486 SelectPen( getHDC(), mhDefPen );
487 mhDefPen = nullptr;
489 if ( mhDefBrush )
491 SelectBrush( getHDC(), mhDefBrush );
492 mhDefBrush = nullptr;
494 if ( mhDefFont )
496 SelectFont( getHDC(), mhDefFont );
497 mhDefFont = nullptr;
499 setPalette(nullptr);
501 mpImpl->DeInit();
504 void WinSalGraphics::setHDC(HDC aNew)
506 DeInitGraphics();
507 mhLocalDC = aNew;
508 InitGraphics();
511 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
513 SalData* pSalData = GetSalData();
514 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
516 if( !pC->mhDC )
518 HDC hDC = GetDC( nullptr );
520 // create new DC with DefaultBitmap
521 pC->mhDC = CreateCompatibleDC( hDC );
523 if( pSalData->mhDitherPal )
525 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
526 RealizePalette( pC->mhDC );
529 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
530 pC->mhDefBmp = static_cast<HBITMAP>(SelectObject( pC->mhDC, pC->mhSelBmp ));
532 ReleaseDC( nullptr, hDC );
535 if ( hBmp )
536 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
537 else
538 pC->mhActBmp = nullptr;
540 return pC->mhDC;
543 void ImplReleaseCachedDC( sal_uLong nID )
545 SalData* pSalData = GetSalData();
546 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
548 if ( pC->mhActBmp )
549 SelectObject( pC->mhDC, pC->mhSelBmp );
552 void ImplClearHDCCache( SalData* pData )
554 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
556 HDCCache* pC = &pData->mpHDCCache[ i ];
558 if( pC->mhDC )
560 SelectObject( pC->mhDC, pC->mhDefBmp );
562 if( pC->mhDefPal )
563 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
565 DeleteDC( pC->mhDC );
566 DeleteObject( pC->mhSelBmp );
571 std::unique_ptr< CompatibleDC > CompatibleDC::create(SalGraphics &rGraphics, int x, int y, int width, int height)
573 #if HAVE_FEATURE_SKIA
574 if (SkiaHelper::isVCLSkiaEnabled())
575 return std::make_unique< SkiaCompatibleDC >( rGraphics, x, y, width, height );
576 #endif
577 return std::unique_ptr< CompatibleDC >( new CompatibleDC( rGraphics, x, y, width, height ));
580 CompatibleDC::CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable)
581 : mhBitmap(nullptr)
582 , mpData(nullptr)
583 , maRects(0, 0, width, height, x, y, width, height)
584 , mpImpl(nullptr)
586 WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
588 if( disable )
590 // we avoid the OpenGL drawing, instead we draw directly to the DC
591 mhCompatibleDC = rWinGraphics.getHDC();
592 return;
595 mpImpl = rWinGraphics.getWinSalGraphicsImplBase();
596 mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
598 // move the origin so that we always paint at 0,0 - to keep the bitmap
599 // small
600 OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
602 mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
604 mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap));
607 CompatibleDC::~CompatibleDC()
609 if (mpImpl)
611 SelectObject(mhCompatibleDC, mhOrigBitmap);
612 DeleteObject(mhBitmap);
613 DeleteDC(mhCompatibleDC);
617 void CompatibleDC::fill(sal_uInt32 color)
619 if (!mpData)
620 return;
622 sal_uInt32 *p = mpData;
623 for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
624 *p++ = color;
627 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, [[maybe_unused]] SalGeometryProvider *pProvider):
628 mhLocalDC(nullptr),
629 mbPrinter(eType == WinSalGraphics::PRINTER),
630 mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
631 mbWindow(eType == WinSalGraphics::WINDOW),
632 mbScreen(bScreen),
633 mhWnd(hWnd),
634 mhRegion(nullptr),
635 mhDefPen(nullptr),
636 mhDefBrush(nullptr),
637 mhDefFont(nullptr),
638 mhDefPal(nullptr),
639 mpStdClipRgnData(nullptr),
640 mnPenWidth(GSL_PEN_WIDTH)
642 #if HAVE_FEATURE_SKIA
643 if (SkiaHelper::isVCLSkiaEnabled() && !mbPrinter)
645 auto const impl = new WinSkiaSalGraphicsImpl(*this, pProvider);
646 mpImpl.reset(impl);
647 mWinSalGraphicsImplBase = impl;
649 else
650 #endif
652 auto const impl = new WinSalGraphicsImpl(*this);
653 mpImpl.reset(impl);
654 mWinSalGraphicsImplBase = impl;
658 WinSalGraphics::~WinSalGraphics()
660 // free obsolete GDI objects
661 ReleaseFonts();
663 if ( mhRegion )
665 DeleteRegion( mhRegion );
666 mhRegion = nullptr;
669 // delete cache data
670 delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
672 setHDC(nullptr);
675 SalGraphicsImpl* WinSalGraphics::GetImpl() const
677 return mpImpl.get();
680 bool WinSalGraphics::isPrinter() const
682 return mbPrinter;
685 bool WinSalGraphics::isVirtualDevice() const
687 return mbVirDev;
690 bool WinSalGraphics::isWindow() const
692 return mbWindow;
695 bool WinSalGraphics::isScreen() const
697 return mbScreen;
700 HWND WinSalGraphics::gethWnd()
702 return mhWnd;
705 void WinSalGraphics::setHWND(HWND hWnd)
707 mhWnd = hWnd;
710 HPALETTE WinSalGraphics::getDefPal() const
712 assert(getHDC() || !mhDefPal);
713 return mhDefPal;
716 UINT WinSalGraphics::setPalette(HPALETTE hNewPal, BOOL bForceBkgd)
718 UINT res = GDI_ERROR;
720 if (!getHDC())
722 assert(!mhDefPal);
723 return res;
726 if (hNewPal)
728 HPALETTE hOldPal = SelectPalette(getHDC(), hNewPal, bForceBkgd);
729 if (hOldPal)
731 if (!mhDefPal)
732 mhDefPal = hOldPal;
733 res = RealizePalette(getHDC());
736 else
738 res = 0;
739 if (mhDefPal)
741 SelectPalette(getHDC(), mhDefPal, bForceBkgd);
742 mhDefPal = nullptr;
746 return res;
749 HRGN WinSalGraphics::getRegion() const
751 return mhRegion;
754 void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
756 rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
757 rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
759 // #111139# this fixes the symptom of div by zero on startup
760 // however, printing will fail most likely as communication with
761 // the printer seems not to work in this case
762 if( !rDPIX || !rDPIY )
763 rDPIX = rDPIY = 600;
766 void WinSalGraphics::getDWriteFactory(IDWriteFactory** pFactory, IDWriteGdiInterop** pInterop)
768 if (!bDWriteDone)
770 HRESULT hr = S_OK;
771 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
772 reinterpret_cast<IUnknown**>(&mxDWriteFactory));
773 if (FAILED(hr))
775 SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
776 << WindowsErrorStringFromHRESULT(hr));
777 abort();
780 hr = mxDWriteFactory->GetGdiInterop(&mxDWriteGdiInterop);
781 if (FAILED(hr))
783 SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
784 << WindowsErrorStringFromHRESULT(hr));
785 abort();
788 bDWriteDone = true;
791 if (pFactory)
792 *pFactory = mxDWriteFactory.get();
793 if (pInterop)
794 *pInterop = mxDWriteGdiInterop.get();
797 sal_uInt16 WinSalGraphics::GetBitCount() const
799 return mpImpl->GetBitCount();
802 tools::Long WinSalGraphics::GetGraphicsWidth() const
804 return mpImpl->GetGraphicsWidth();
807 void WinSalGraphics::Flush()
809 mWinSalGraphicsImplBase->Flush();
812 void WinSalGraphics::ResetClipRegion()
814 mpImpl->ResetClipRegion();
817 bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
819 return mpImpl->setClipRegion( i_rClip );
822 void WinSalGraphics::SetLineColor()
824 mpImpl->SetLineColor();
827 void WinSalGraphics::SetLineColor( Color nColor )
829 mpImpl->SetLineColor( nColor );
832 void WinSalGraphics::SetFillColor()
834 mpImpl->SetFillColor();
837 void WinSalGraphics::SetFillColor( Color nColor )
839 mpImpl->SetFillColor( nColor );
842 void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
844 mpImpl->SetXORMode( bSet, bInvertOnly );
847 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
849 mpImpl->SetROPLineColor( nROPColor );
852 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
854 mpImpl->SetROPFillColor( nROPColor );
857 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY )
859 mpImpl->drawPixel( nX, nY );
862 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
864 mpImpl->drawPixel( nX, nY, nColor );
867 void WinSalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
869 mpImpl->drawLine( nX1, nY1, nX2, nY2 );
872 void WinSalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
874 mpImpl->drawRect( nX, nY, nWidth, nHeight );
877 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry )
879 mpImpl->drawPolyLine( nPoints, pPtAry );
882 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
884 mpImpl->drawPolygon( nPoints, pPtAry );
887 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
888 const Point** pPtAry )
890 mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
893 bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
895 return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
898 bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
900 return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
903 bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
904 const Point* const* pPtAry, const PolyFlags* const* pFlgAry )
906 return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
909 bool WinSalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
911 return mpImpl->drawGradient(rPoly, rGradient);
914 bool WinSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
916 return mpImpl->implDrawGradient(rPolyPolygon, rGradient);
919 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize )
921 while ( nComp-- >= nSize )
923 sal_uLong i;
924 for ( i = 0; i < nSize; i++ )
926 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
927 break;
929 if ( i == nSize )
930 return pSource;
931 pSource++;
933 return nullptr;
936 static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
938 bool bRetValue = false;
939 BYTE* pDest = ImplSearchEntry( pSource, reinterpret_cast<BYTE const *>("%%BoundingBox:"), nSize, 14 );
940 if ( pDest )
942 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
943 pDest += 14;
945 int nSizeLeft = nSize - ( pDest - pSource );
946 if ( nSizeLeft > 100 )
947 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
949 int i;
950 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
952 int nDivision = 1;
953 bool bDivision = false;
954 bool bNegative = false;
955 bool bValid = true;
957 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
958 BYTE nByte = *pDest;
959 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
961 switch ( nByte )
963 case '.' :
964 if ( bDivision )
965 bValid = false;
966 else
967 bDivision = true;
968 break;
969 case '-' :
970 bNegative = true;
971 break;
972 default :
973 if ( ( nByte < '0' ) || ( nByte > '9' ) )
974 nSizeLeft = 1; // error parsing the bounding box values
975 else if ( bValid )
977 if ( bDivision )
978 nDivision*=10;
979 nNumb[i] *= 10;
980 nNumb[i] += nByte - '0';
982 break;
984 nSizeLeft--;
985 nByte = *(++pDest);
987 if ( bNegative )
988 nNumb[i] = -nNumb[i];
989 if ( bDivision && ( nDivision != 1 ) )
990 nNumb[i] /= nDivision;
992 if ( i == 4 )
993 bRetValue = true;
995 return bRetValue;
998 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
1000 bool WinSalGraphics::drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize )
1002 bool bRetValue = false;
1004 if ( mbPrinter )
1006 int nEscape = POSTSCRIPT_PASSTHROUGH;
1008 if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), reinterpret_cast<LPSTR>(&nEscape), nullptr ) )
1010 double nBoundingBox[4];
1012 if ( ImplGetBoundingBox( nBoundingBox, static_cast<BYTE*>(pPtr), nSize ) )
1014 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1016 // reserve place for a sal_uInt16
1017 aBuf.append( "aa" );
1019 // #107797# Write out EPS encapsulation header
1021 // directly taken from the PLRM 3.0, p. 726. Note:
1022 // this will definitely cause problems when
1023 // recursively creating and embedding PostScript files
1024 // in OOo, since we use statically-named variables
1025 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1026 // op_count_salWin). Currently, I have no idea on how to
1027 // work around that, except from scanning and
1028 // interpreting the EPS for unused identifiers.
1030 // append the real text
1031 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1032 "/dict_count_salWin countdictstack def\n"
1033 "/op_count_salWin count 1 sub def\n"
1034 "userdict begin\n"
1035 "/showpage {} def\n"
1036 "0 setgray 0 setlinecap\n"
1037 "1 setlinewidth 0 setlinejoin\n"
1038 "10 setmiterlimit [] 0 setdash newpath\n"
1039 "/languagelevel where\n"
1040 "{\n"
1041 " pop languagelevel\n"
1042 " 1 ne\n"
1043 " {\n"
1044 " false setstrokeadjust false setoverprint\n"
1045 " } if\n"
1046 "} if\n\n" );
1048 // #i10737# Apply clipping manually
1050 // Windows seems to ignore any clipping at the HDC,
1051 // when followed by a POSTSCRIPT_PASSTHROUGH
1053 // Check whether we've got a clipping, consisting of
1054 // exactly one rect (other cases should be, but aren't
1055 // handled currently)
1057 // TODO: Handle more than one rectangle here (take
1058 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1059 // characters!)
1060 if ( mhRegion != nullptr &&
1061 mpStdClipRgnData != nullptr &&
1062 mpClipRgnData == mpStdClipRgnData &&
1063 mpClipRgnData->rdh.nCount == 1 )
1065 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1067 aBuf.append( "\nnewpath\n" );
1068 aBuf.append( pRect->left );
1069 aBuf.append( " " );
1070 aBuf.append( pRect->top );
1071 aBuf.append( " moveto\n" );
1072 aBuf.append( pRect->right );
1073 aBuf.append( " " );
1074 aBuf.append( pRect->top );
1075 aBuf.append( " lineto\n" );
1076 aBuf.append( pRect->right );
1077 aBuf.append( " " );
1078 aBuf.append( pRect->bottom );
1079 aBuf.append( " lineto\n" );
1080 aBuf.append( pRect->left );
1081 aBuf.append( " " );
1082 aBuf.append( pRect->bottom );
1083 aBuf.append( " lineto\n"
1084 "closepath\n"
1085 "clip\n"
1086 "newpath\n" );
1089 // #107797# Write out buffer
1091 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1092 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1094 // #107797# Write out EPS transformation code
1096 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1097 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1098 // reserve a sal_uInt16 again
1099 aBuf.setLength( 2 );
1100 aBuf.append( "\n\n[" );
1101 aBuf.append( dM11 );
1102 aBuf.append( " 0 0 " );
1103 aBuf.append( dM22 );
1104 aBuf.append( ' ' );
1105 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1106 aBuf.append( ' ' );
1107 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1108 aBuf.append( "] concat\n"
1109 "%%BeginDocument:\n" );
1110 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1111 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1113 // #107797# Write out actual EPS content
1115 sal_uLong nToDo = nSize;
1116 sal_uLong nDoNow;
1117 while ( nToDo )
1119 nDoNow = nToDo;
1120 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1121 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1122 // the following is based on the string buffer allocation
1123 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1124 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>(nDoNow);
1125 memcpy( const_cast<char *>(aBuf.getStr() + 2), static_cast<BYTE*>(pPtr) + nSize - nToDo, nDoNow );
1126 sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, aBuf.getStr(), nullptr );
1127 if (!nResult )
1128 break;
1129 nToDo -= nResult;
1132 // #107797# Write out EPS encapsulation footer
1134 // reserve a sal_uInt16 again
1135 aBuf.setLength( 2 );
1136 aBuf.append( "%%EndDocument\n"
1137 "count op_count_salWin sub {pop} repeat\n"
1138 "countdictstack dict_count_salWin sub {end} repeat\n"
1139 "b4_Inc_state_salWin restore\n\n" );
1140 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1141 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1142 bRetValue = true;
1147 return bRetValue;
1150 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1152 SystemGraphicsData aRes;
1153 aRes.nSize = sizeof(aRes);
1154 aRes.hDC = getHDC();
1155 return aRes;
1158 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */