tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / vcl / win / gdi / salgdi.cxx
blob1040810975c6ba7054c187fd56dad3c344aa4fd4
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 temporary font lists
138 pSalData->mpSharedTempFontItem = nullptr;
139 pSalData->mpOtherTempFontItem = nullptr;
141 // support palettes for 256 color displays
142 HDC hDC = GetDC( nullptr );
143 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
144 int nPlanes = GetDeviceCaps( hDC, PLANES );
145 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
146 int nBitCount = nBitsPixel * nPlanes;
148 if ( (nBitCount > 8) && (nBitCount < 24) )
150 // test if we have to dither
151 HDC hMemDC = ::CreateCompatibleDC( hDC );
152 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
153 HBITMAP hBmpOld = static_cast<HBITMAP>(::SelectObject( hMemDC, hMemBmp ));
154 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
155 HBRUSH hBrushOld = static_cast<HBRUSH>(::SelectObject( hMemDC, hMemBrush ));
156 bool bDither16 = true;
158 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
159 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
161 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
162 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
163 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
164 bDither16 = false;
166 ::SelectObject( hMemDC, hBrushOld );
167 ::DeleteObject( hMemBrush );
168 ::SelectObject( hMemDC, hBmpOld );
169 ::DeleteObject( hMemBmp );
170 ::DeleteDC( hMemDC );
172 if( bDither16 )
174 // create DIBPattern for 16Bit dithering
175 tools::Long n;
177 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
178 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
179 pSalData->mpDitherDiff.reset(new tools::Long[ 256 ]);
180 pSalData->mpDitherLow.reset(new BYTE[ 256 ]);
181 pSalData->mpDitherHigh.reset(new BYTE[ 256 ]);
182 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
183 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
185 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
187 pBIH->biSize = sizeof( BITMAPINFOHEADER );
188 pBIH->biWidth = 8;
189 pBIH->biHeight = 8;
190 pBIH->biPlanes = 1;
191 pBIH->biBitCount = 24;
193 for( n = 0; n < 256; n++ )
194 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
196 for( n = 0; n < 256; n++ )
197 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n & 248 );
199 for( n = 0; n < 256; n++ )
200 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 8, 255 ));
203 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
205 BYTE nRed, nGreen, nBlue;
206 BYTE nR, nG, nB;
207 PALETTEENTRY* pPalEntry;
208 LOGPALETTE* pLogPal;
209 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
210 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
212 // create logical palette
213 pLogPal = reinterpret_cast<LOGPALETTE*>(new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ]);
214 pLogPal->palVersion = 0x0300;
215 pLogPal->palNumEntries = static_cast<sal_uInt16>(nTotalCount);
216 pPalEntry = pLogPal->palPalEntry;
218 // Standard colors
219 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
220 pPalEntry += DITHER_MAX_SYSCOLOR;
222 // own palette (6/6/6)
223 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
225 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
227 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
229 pPalEntry->peRed = nRed;
230 pPalEntry->peGreen = nGreen;
231 pPalEntry->peBlue = nBlue;
232 pPalEntry->peFlags = 0;
233 pPalEntry++;
238 // insert special 'Blue' as standard drawing color
239 *pPalEntry++ = aImplExtraColor1;
241 // create palette
242 pSalData->mhDitherPal = CreatePalette( pLogPal );
243 delete[] reinterpret_cast<char*>(pLogPal);
245 if( pSalData->mhDitherPal )
247 // create DIBPattern for 8Bit dithering
248 tools::Long const nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
249 tools::Long n;
251 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
252 pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
253 pSalData->mpDitherDiff.reset(new tools::Long[ 256 ]);
254 pSalData->mpDitherLow.reset(new BYTE[ 256 ]);
255 pSalData->mpDitherHigh.reset(new BYTE[ 256 ]);
256 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
257 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
259 BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
260 short* pColors = reinterpret_cast<short*>( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
262 pBIH->biSize = sizeof( BITMAPINFOHEADER );
263 pBIH->biWidth = 8;
264 pBIH->biHeight = 8;
265 pBIH->biPlanes = 1;
266 pBIH->biBitCount = 8;
268 for( n = 0; n < nDitherPalCount; n++ )
269 pColors[ n ] = static_cast<short>( n + DITHER_MAX_SYSCOLOR );
271 for( n = 0; n < 256; n++ )
272 pSalData->mpDitherDiff[ n ] = n % 51;
274 for( n = 0; n < 256; n++ )
275 pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n / 51 );
277 for( n = 0; n < 256; n++ )
278 pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 1, 5 ));
281 // get system color entries
282 ImplUpdateSysColorEntries();
285 ReleaseDC( nullptr, hDC );
288 void ImplFreeSalGDI()
290 SalData* pSalData = GetSalData();
292 if (pSalData->mbResourcesAlreadyFreed)
293 return;
295 // destroy stock objects
296 int i;
297 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
298 DeletePen( pSalData->mhStockPenAry[i] );
299 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
300 DeleteBrush( pSalData->mhStockBrushAry[i] );
302 // delete 50% Brush
303 if ( pSalData->mh50Brush )
305 DeleteBrush( pSalData->mh50Brush );
306 pSalData->mh50Brush = nullptr;
309 // delete 50% Bitmap
310 if ( pSalData->mh50Bmp )
312 DeleteBitmap( pSalData->mh50Bmp );
313 pSalData->mh50Bmp = nullptr;
316 ImplClearHDCCache( pSalData );
318 // delete Ditherpalette, if existing
319 if ( pSalData->mhDitherPal )
321 DeleteObject( pSalData->mhDitherPal );
322 pSalData->mhDitherPal = nullptr;
325 // delete buffers for dithering DIB patterns, if necessary
326 if ( pSalData->mhDitherDIB )
328 GlobalUnlock( pSalData->mhDitherDIB );
329 GlobalFree( pSalData->mhDitherDIB );
330 pSalData->mhDitherDIB = nullptr;
331 pSalData->mpDitherDiff.reset();
332 pSalData->mpDitherLow.reset();
333 pSalData->mpDitherHigh.reset();
336 DeleteSysColorList();
338 // delete icon cache
339 SalIcon* pIcon = pSalData->mpFirstIcon;
340 pSalData->mpFirstIcon = nullptr;
341 while( pIcon )
343 SalIcon* pTmp = pIcon->pNext;
344 DestroyIcon( pIcon->hIcon );
345 DestroyIcon( pIcon->hSmallIcon );
346 delete pIcon;
347 pIcon = pTmp;
350 // delete temporary font list
351 ImplReleaseTempFonts(*pSalData, true);
353 pSalData->mbResourcesAlreadyFreed = true;
356 int ImplIsSysColorEntry( Color nColor )
358 SysColorEntry* pEntry = pFirstSysColor;
359 const DWORD nTestRGB = static_cast<DWORD>(RGB( nColor.GetRed(),
360 nColor.GetGreen(),
361 nColor.GetBlue() ));
363 while ( pEntry )
365 if ( pEntry->nRGB == nTestRGB )
366 return TRUE;
367 pEntry = pEntry->pNext;
370 return FALSE;
373 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
375 // dither color?
376 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
377 return TRUE;
379 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
381 // standard palette color?
382 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
384 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
385 return TRUE;
388 // extra color?
389 if ( aImplExtraColor1.peRed == nRed &&
390 aImplExtraColor1.peGreen == nGreen &&
391 aImplExtraColor1.peBlue == nBlue )
393 return TRUE;
396 return FALSE;
399 static void ImplInsertSysColorEntry( int nSysIndex )
401 const DWORD nRGB = GetSysColor( nSysIndex );
403 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
405 if ( !pFirstSysColor )
407 pActSysColor = pFirstSysColor = new SysColorEntry;
408 pFirstSysColor->nRGB = nRGB;
409 pFirstSysColor->pNext = nullptr;
411 else
413 pActSysColor = pActSysColor->pNext = new SysColorEntry;
414 pActSysColor->nRGB = nRGB;
415 pActSysColor->pNext = nullptr;
420 void ImplUpdateSysColorEntries()
422 DeleteSysColorList();
424 // create new sys color list
425 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
426 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
427 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
428 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
429 ImplInsertSysColorEntry( COLOR_3DFACE );
430 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
431 ImplInsertSysColorEntry( COLOR_3DLIGHT );
432 ImplInsertSysColorEntry( COLOR_3DSHADOW );
433 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
434 ImplInsertSysColorEntry( COLOR_INFOBK );
435 ImplInsertSysColorEntry( COLOR_INFOTEXT );
436 ImplInsertSysColorEntry( COLOR_BTNTEXT );
437 ImplInsertSysColorEntry( COLOR_WINDOW );
438 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
439 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
440 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
441 ImplInsertSysColorEntry( COLOR_MENU );
442 ImplInsertSysColorEntry( COLOR_MENUTEXT );
443 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
444 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
445 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
446 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
449 void WinSalGraphics::InitGraphics()
451 if (!getHDC())
452 return;
454 // calculate the minimal line width for the printer
455 if ( isPrinter() )
457 int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
458 if ( nDPIX <= 300 )
459 mnPenWidth = 0;
460 else
461 mnPenWidth = nDPIX/300;
464 ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
465 ::SetBkMode( getHDC(), TRANSPARENT );
466 ::SetROP2( getHDC(), R2_COPYPEN );
469 void WinSalGraphics::DeInitGraphics()
471 if (!getHDC())
472 return;
474 // clear clip region
475 SelectClipRgn( getHDC(), nullptr );
476 // select default objects
477 if ( mhDefPen )
479 SelectPen( getHDC(), mhDefPen );
480 mhDefPen = nullptr;
482 if ( mhDefBrush )
484 SelectBrush( getHDC(), mhDefBrush );
485 mhDefBrush = nullptr;
487 if ( mhDefFont )
489 SelectFont( getHDC(), mhDefFont );
490 mhDefFont = nullptr;
492 setPalette(nullptr);
494 mpImpl->DeInit();
497 void WinSalGraphics::setHDC(HDC aNew)
499 DeInitGraphics();
500 mhLocalDC = aNew;
501 InitGraphics();
504 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
506 SalData* pSalData = GetSalData();
507 HDCCache* pC = &pSalData->maHDCCache[ nID ];
509 if( !pC->mhDC )
511 HDC hDC = GetDC( nullptr );
513 // create new DC with DefaultBitmap
514 pC->mhDC = CreateCompatibleDC( hDC );
516 if( pSalData->mhDitherPal )
518 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
519 RealizePalette( pC->mhDC );
522 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
523 pC->mhDefBmp = static_cast<HBITMAP>(SelectObject( pC->mhDC, pC->mhSelBmp ));
525 ReleaseDC( nullptr, hDC );
528 if ( hBmp )
529 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
530 else
531 pC->mhActBmp = nullptr;
533 return pC->mhDC;
536 void ImplReleaseCachedDC( sal_uLong nID )
538 SalData* pSalData = GetSalData();
539 HDCCache* pC = &pSalData->maHDCCache[ nID ];
541 if ( pC->mhActBmp )
542 SelectObject( pC->mhDC, pC->mhSelBmp );
545 void ImplClearHDCCache( SalData* pData )
547 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
549 HDCCache* pC = &pData->maHDCCache[ i ];
551 if( pC->mhDC )
553 SelectObject( pC->mhDC, pC->mhDefBmp );
555 if( pC->mhDefPal )
556 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
558 DeleteDC( pC->mhDC );
559 DeleteObject( pC->mhSelBmp );
564 std::unique_ptr< CompatibleDC > CompatibleDC::create(SalGraphics &rGraphics, int x, int y, int width, int height)
566 #if HAVE_FEATURE_SKIA
567 if (SkiaHelper::isVCLSkiaEnabled())
568 return std::make_unique< SkiaCompatibleDC >( rGraphics, x, y, width, height );
569 #endif
570 return std::unique_ptr< CompatibleDC >( new CompatibleDC( rGraphics, x, y, width, height ));
573 CompatibleDC::CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable)
574 : mhBitmap(nullptr)
575 , mpData(nullptr)
576 , maRects(0, 0, width, height, x, y, width, height)
577 , mpImpl(nullptr)
579 WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
581 if( disable )
583 // we avoid the OpenGL drawing, instead we draw directly to the DC
584 mhCompatibleDC = rWinGraphics.getHDC();
585 return;
588 mpImpl = rWinGraphics.getWinSalGraphicsImplBase();
589 mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
591 // move the origin so that we always paint at 0,0 - to keep the bitmap
592 // small
593 OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
595 mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
597 mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap));
600 CompatibleDC::~CompatibleDC()
602 if (mpImpl)
604 SelectObject(mhCompatibleDC, mhOrigBitmap);
605 DeleteObject(mhBitmap);
606 DeleteDC(mhCompatibleDC);
610 void CompatibleDC::fill(sal_uInt32 color)
612 if (!mpData)
613 return;
615 sal_uInt32 *p = mpData;
616 for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
617 *p++ = color;
620 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, [[maybe_unused]] SalGeometryProvider *pProvider):
621 mhLocalDC(nullptr),
622 mbPrinter(eType == WinSalGraphics::PRINTER),
623 mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
624 mbWindow(eType == WinSalGraphics::WINDOW),
625 mbScreen(bScreen),
626 mhWnd(hWnd),
627 mhRegion(nullptr),
628 mhDefPen(nullptr),
629 mhDefBrush(nullptr),
630 mhDefFont(nullptr),
631 mhDefPal(nullptr),
632 mpStdClipRgnData(nullptr),
633 mnPenWidth(GSL_PEN_WIDTH)
635 #if HAVE_FEATURE_SKIA
636 if (SkiaHelper::isVCLSkiaEnabled() && !mbPrinter)
638 auto const impl = new WinSkiaSalGraphicsImpl(*this, pProvider);
639 mpImpl.reset(impl);
640 mWinSalGraphicsImplBase = impl;
642 else
643 #endif
645 auto const impl = new WinSalGraphicsImpl(*this);
646 mpImpl.reset(impl);
647 mWinSalGraphicsImplBase = impl;
651 WinSalGraphics::~WinSalGraphics()
653 // free obsolete GDI objects
654 ReleaseFonts();
656 if ( mhRegion )
658 DeleteRegion( mhRegion );
659 mhRegion = nullptr;
662 // delete cache data
663 delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
665 setHDC(nullptr);
668 SalGraphicsImpl* WinSalGraphics::GetImpl() const
670 return mpImpl.get();
673 bool WinSalGraphics::isPrinter() const
675 return mbPrinter;
678 bool WinSalGraphics::isVirtualDevice() const
680 return mbVirDev;
683 bool WinSalGraphics::isWindow() const
685 return mbWindow;
688 bool WinSalGraphics::isScreen() const
690 return mbScreen;
693 HWND WinSalGraphics::gethWnd()
695 return mhWnd;
698 void WinSalGraphics::setHWND(HWND hWnd)
700 mhWnd = hWnd;
703 HPALETTE WinSalGraphics::getDefPal() const
705 assert(getHDC() || !mhDefPal);
706 return mhDefPal;
709 UINT WinSalGraphics::setPalette(HPALETTE hNewPal, BOOL bForceBkgd)
711 UINT res = GDI_ERROR;
713 if (!getHDC())
715 assert(!mhDefPal);
716 return res;
719 if (hNewPal)
721 HPALETTE hOldPal = SelectPalette(getHDC(), hNewPal, bForceBkgd);
722 if (hOldPal)
724 if (!mhDefPal)
725 mhDefPal = hOldPal;
726 res = RealizePalette(getHDC());
729 else
731 res = 0;
732 if (mhDefPal)
734 SelectPalette(getHDC(), mhDefPal, bForceBkgd);
735 mhDefPal = nullptr;
739 return res;
742 HRGN WinSalGraphics::getRegion() const
744 return mhRegion;
747 void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
749 rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
750 rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
752 // #111139# this fixes the symptom of div by zero on startup
753 // however, printing will fail most likely as communication with
754 // the printer seems not to work in this case
755 if( !rDPIX || !rDPIY )
756 rDPIX = rDPIY = 600;
759 // static
760 IDWriteFactory* WinSalGraphics::getDWriteFactory()
762 static sal::systools::COMReference<IDWriteFactory> pDWriteFactory(
763 []()
765 sal::systools::COMReference<IDWriteFactory> pResult;
766 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
767 reinterpret_cast<IUnknown**>(&pResult));
768 if (FAILED(hr))
770 SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
771 << WindowsErrorStringFromHRESULT(hr));
772 abort();
774 return pResult;
775 }());
776 return pDWriteFactory.get();
779 // static
780 IDWriteGdiInterop* WinSalGraphics::getDWriteGdiInterop()
782 static sal::systools::COMReference<IDWriteGdiInterop> pDWriteGdiInterop(
783 []()
785 sal::systools::COMReference<IDWriteGdiInterop> pResult;
786 HRESULT hr = getDWriteFactory()->GetGdiInterop(&pResult);
787 if (FAILED(hr))
789 SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
790 << WindowsErrorStringFromHRESULT(hr));
791 abort();
793 return pResult;
794 }());
795 return pDWriteGdiInterop.get();
798 sal_uInt16 WinSalGraphics::GetBitCount() const
800 return mpImpl->GetBitCount();
803 tools::Long WinSalGraphics::GetGraphicsWidth() const
805 return mpImpl->GetGraphicsWidth();
808 void WinSalGraphics::Flush()
810 mWinSalGraphicsImplBase->Flush();
813 void WinSalGraphics::ResetClipRegion()
815 mpImpl->ResetClipRegion();
818 void WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
820 mpImpl->setClipRegion( i_rClip );
823 void WinSalGraphics::SetLineColor()
825 mpImpl->SetLineColor();
828 void WinSalGraphics::SetLineColor( Color nColor )
830 mpImpl->SetLineColor( nColor );
833 void WinSalGraphics::SetFillColor()
835 mpImpl->SetFillColor();
838 void WinSalGraphics::SetFillColor( Color nColor )
840 mpImpl->SetFillColor( nColor );
843 void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
845 mpImpl->SetXORMode( bSet, bInvertOnly );
848 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
850 mpImpl->SetROPLineColor( nROPColor );
853 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
855 mpImpl->SetROPFillColor( nROPColor );
858 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY )
860 mpImpl->drawPixel( nX, nY );
863 void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
865 mpImpl->drawPixel( nX, nY, nColor );
868 void WinSalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
870 mpImpl->drawLine( nX1, nY1, nX2, nY2 );
873 void WinSalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
875 mpImpl->drawRect( nX, nY, nWidth, nHeight );
878 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry )
880 mpImpl->drawPolyLine( nPoints, pPtAry );
883 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
885 mpImpl->drawPolygon( nPoints, pPtAry );
888 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
889 const Point** pPtAry )
891 mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
894 bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
896 return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
899 bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
901 return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
904 bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
905 const Point* const* pPtAry, const PolyFlags* const* pFlgAry )
907 return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
910 bool WinSalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
912 return mpImpl->drawGradient(rPoly, rGradient);
915 bool WinSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
917 return mpImpl->implDrawGradient(rPolyPolygon, rGradient);
920 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize )
922 while ( nComp-- >= nSize )
924 sal_uLong i;
925 for ( i = 0; i < nSize; i++ )
927 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
928 break;
930 if ( i == nSize )
931 return pSource;
932 pSource++;
934 return nullptr;
937 static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
939 bool bRetValue = false;
940 BYTE* pDest = ImplSearchEntry( pSource, reinterpret_cast<BYTE const *>("%%BoundingBox:"), nSize, 14 );
941 if ( pDest )
943 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
944 pDest += 14;
946 int nSizeLeft = nSize - ( pDest - pSource );
947 if ( nSizeLeft > 100 )
948 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
950 int i;
951 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
953 int nDivision = 1;
954 bool bDivision = false;
955 bool bNegative = false;
956 bool bValid = true;
958 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
959 BYTE nByte = *pDest;
960 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
962 switch ( nByte )
964 case '.' :
965 if ( bDivision )
966 bValid = false;
967 else
968 bDivision = true;
969 break;
970 case '-' :
971 bNegative = true;
972 break;
973 default :
974 if ( ( nByte < '0' ) || ( nByte > '9' ) )
975 nSizeLeft = 1; // error parsing the bounding box values
976 else if ( bValid )
978 if ( bDivision )
979 nDivision*=10;
980 nNumb[i] *= 10;
981 nNumb[i] += nByte - '0';
983 break;
985 nSizeLeft--;
986 nByte = *(++pDest);
988 if ( bNegative )
989 nNumb[i] = -nNumb[i];
990 if ( bDivision && ( nDivision != 1 ) )
991 nNumb[i] /= nDivision;
993 if ( i == 4 )
994 bRetValue = true;
996 return bRetValue;
999 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
1001 bool WinSalGraphics::drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize )
1003 bool bRetValue = false;
1005 if ( mbPrinter )
1007 int nEscape = POSTSCRIPT_PASSTHROUGH;
1009 if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), reinterpret_cast<LPSTR>(&nEscape), nullptr ) )
1011 double nBoundingBox[4];
1013 if ( ImplGetBoundingBox( nBoundingBox, static_cast<BYTE*>(pPtr), nSize ) )
1015 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
1017 // reserve place for a sal_uInt16
1018 aBuf.append( "aa" );
1020 // #107797# Write out EPS encapsulation header
1022 // directly taken from the PLRM 3.0, p. 726. Note:
1023 // this will definitely cause problems when
1024 // recursively creating and embedding PostScript files
1025 // in OOo, since we use statically-named variables
1026 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
1027 // op_count_salWin). Currently, I have no idea on how to
1028 // work around that, except from scanning and
1029 // interpreting the EPS for unused identifiers.
1031 // append the real text
1032 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
1033 "/dict_count_salWin countdictstack def\n"
1034 "/op_count_salWin count 1 sub def\n"
1035 "userdict begin\n"
1036 "/showpage {} def\n"
1037 "0 setgray 0 setlinecap\n"
1038 "1 setlinewidth 0 setlinejoin\n"
1039 "10 setmiterlimit [] 0 setdash newpath\n"
1040 "/languagelevel where\n"
1041 "{\n"
1042 " pop languagelevel\n"
1043 " 1 ne\n"
1044 " {\n"
1045 " false setstrokeadjust false setoverprint\n"
1046 " } if\n"
1047 "} if\n\n" );
1049 // #i10737# Apply clipping manually
1051 // Windows seems to ignore any clipping at the HDC,
1052 // when followed by a POSTSCRIPT_PASSTHROUGH
1054 // Check whether we've got a clipping, consisting of
1055 // exactly one rect (other cases should be, but aren't
1056 // handled currently)
1058 // TODO: Handle more than one rectangle here (take
1059 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
1060 // characters!)
1061 if ( mhRegion != nullptr &&
1062 mpStdClipRgnData != nullptr &&
1063 mpClipRgnData == mpStdClipRgnData &&
1064 mpClipRgnData->rdh.nCount == 1 )
1066 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
1068 aBuf.append( "\nnewpath\n"
1069 + OString::number(pRect->left) + " " + OString::number(pRect->top)
1070 + " moveto\n"
1071 + OString::number(pRect->right) + " " + OString::number(pRect->top)
1072 + " lineto\n"
1073 + OString::number(pRect->right) + " "
1074 + OString::number(pRect->bottom) + " lineto\n"
1075 + OString::number(pRect->left) + " "
1076 + OString::number(pRect->bottom) + " lineto\n"
1077 "closepath\n"
1078 "clip\n"
1079 "newpath\n" );
1082 // #107797# Write out buffer
1084 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1085 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1087 // #107797# Write out EPS transformation code
1089 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1090 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1091 // reserve a sal_uInt16 again
1092 aBuf.setLength( 2 );
1093 aBuf.append( "\n\n[" + OString::number(dM11) + " 0 0 " + OString::number(dM22) + " "
1094 + OString::number(nX - ( dM11 * nBoundingBox[0] )) + " "
1095 + OString::number(nY - ( dM22 * nBoundingBox[3] )) + "] concat\n"
1096 "%%BeginDocument:\n" );
1097 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1098 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1100 // #107797# Write out actual EPS content
1102 sal_uLong nToDo = nSize;
1103 sal_uLong nDoNow;
1104 while ( nToDo )
1106 nDoNow = nToDo;
1107 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1108 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1109 // the following is based on the string buffer allocation
1110 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1111 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>(nDoNow);
1112 memcpy( const_cast<char *>(aBuf.getStr() + 2), static_cast<BYTE*>(pPtr) + nSize - nToDo, nDoNow );
1113 sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, aBuf.getStr(), nullptr );
1114 if (!nResult )
1115 break;
1116 nToDo -= nResult;
1119 // #107797# Write out EPS encapsulation footer
1121 // reserve a sal_uInt16 again
1122 aBuf.setLength( 2 );
1123 aBuf.append( "%%EndDocument\n"
1124 "count op_count_salWin sub {pop} repeat\n"
1125 "countdictstack dict_count_salWin sub {end} repeat\n"
1126 "b4_Inc_state_salWin restore\n\n" );
1127 *reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
1128 Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
1129 bRetValue = true;
1134 return bRetValue;
1137 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1139 SystemGraphicsData aRes;
1140 aRes.nSize = sizeof(aRes);
1141 aRes.hDC = getHDC();
1142 return aRes;
1145 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */