Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / gdi / salgdi.cxx
blob3ed0c073c05c693adfeb278759c15729454137a8
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 <stdio.h>
21 #include <string.h>
22 #include <svsys.h>
23 #include <rtl/strbuf.hxx>
24 #include <tools/debug.hxx>
25 #include <tools/poly.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/polygon/b2dpolypolygontools.hxx>
29 #include <win/wincomp.hxx>
30 #include <win/saldata.hxx>
31 #include <win/salgdi.h>
32 #include <win/salframe.h>
33 #include <win/salvd.h>
34 #include <basegfx/matrix/b2dhommatrixtools.hxx>
36 #include "salgdiimpl.hxx"
37 #include "gdiimpl.hxx"
38 #include "opengl/win/gdiimpl.hxx"
39 #include <config_cairo_canvas.h>
40 #if ENABLE_CAIRO_CANVAS
41 #include "cairo_win32_cairo.cxx"
42 #endif
44 #include <vcl/opengl/OpenGLHelper.hxx>
47 #define DITHER_PAL_DELTA 51
48 #define DITHER_PAL_STEPS 6
49 #define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
50 #define DITHER_MAX_SYSCOLOR 16
51 #define DITHER_EXTRA_COLORS 1
52 #define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
54 struct SysColorEntry
56 DWORD nRGB;
57 SysColorEntry* pNext;
60 static SysColorEntry* pFirstSysColor = NULL;
61 static SysColorEntry* pActSysColor = NULL;
63 // Blue7
64 static PALETTEENTRY aImplExtraColor1 =
66 0, 184, 255, 0
69 static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
71 { 0, 0, 0, 0 },
72 { 0, 0, 0x80, 0 },
73 { 0, 0x80, 0, 0 },
74 { 0, 0x80, 0x80, 0 },
75 { 0x80, 0, 0, 0 },
76 { 0x80, 0, 0x80, 0 },
77 { 0x80, 0x80, 0, 0 },
78 { 0x80, 0x80, 0x80, 0 },
79 { 0xC0, 0xC0, 0xC0, 0 },
80 { 0, 0, 0xFF, 0 },
81 { 0, 0xFF, 0, 0 },
82 { 0, 0xFF, 0xFF, 0 },
83 { 0xFF, 0, 0, 0 },
84 { 0xFF, 0, 0xFF, 0 },
85 { 0xFF, 0xFF, 0, 0 },
86 { 0xFF, 0xFF, 0xFF, 0 }
89 static BYTE aOrdDither8Bit[8][8] =
91 { 0, 38, 9, 48, 2, 40, 12, 50 },
92 { 25, 12, 35, 22, 28, 15, 37, 24 },
93 { 6, 44, 3, 41, 8, 47, 5, 44 },
94 { 32, 19, 28, 16, 34, 21, 31, 18 },
95 { 1, 40, 11, 49, 0, 39, 10, 48 },
96 { 27, 14, 36, 24, 26, 13, 36, 23 },
97 { 8, 46, 4, 43, 7, 45, 4, 42 },
98 { 33, 20, 30, 17, 32, 20, 29, 16 }
101 static BYTE aOrdDither16Bit[8][8] =
103 { 0, 6, 1, 7, 0, 6, 1, 7 },
104 { 4, 2, 5, 3, 4, 2, 5, 3 },
105 { 1, 7, 0, 6, 1, 7, 0, 6 },
106 { 5, 3, 4, 2, 5, 3, 4, 2 },
107 { 0, 6, 1, 7, 0, 6, 1, 7 },
108 { 4, 2, 5, 3, 4, 2, 5, 3 },
109 { 1, 7, 0, 6, 1, 7, 0, 6 },
110 { 5, 3, 4, 2, 5, 3, 4, 2 }
113 // we must create pens with 1-pixel width; otherwise the S3-graphics card
114 // map has many paint problems when drawing polygons/polyLines and a
115 // complex is set
116 #define GSL_PEN_WIDTH 1
118 void ImplInitSalGDI()
120 SalData* pSalData = GetSalData();
122 pSalData->mbResourcesAlreadyFreed = false;
124 // init stock brushes
125 pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
126 pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
127 pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
128 pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
129 pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
130 pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
131 pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
132 pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
133 pSalData->mnStockPenCount = 4;
135 pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
136 pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
137 pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
138 pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
139 pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
140 pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
141 pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
142 pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
143 pSalData->mnStockBrushCount = 4;
145 // initialize cache of device contexts
146 pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
147 memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
149 // initialize temporary font list
150 pSalData->mpTempFontItem = NULL;
152 // support palettes for 256 color displays
153 HDC hDC = GetDC( 0 );
154 int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
155 int nPlanes = GetDeviceCaps( hDC, PLANES );
156 int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
157 int nBitCount = nBitsPixel * nPlanes;
159 if ( (nBitCount > 8) && (nBitCount < 24) )
161 // test if we have to dither
162 HDC hMemDC = ::CreateCompatibleDC( hDC );
163 HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
164 HBITMAP hBmpOld = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
165 HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
166 HBRUSH hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
167 bool bDither16 = TRUE;
169 ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
170 const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
172 for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
173 for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
174 if( ::GetPixel( hMemDC, nX, nY ) != aCol )
175 bDither16 = FALSE;
177 ::SelectObject( hMemDC, hBrushOld ), ::DeleteObject( hMemBrush );
178 ::SelectObject( hMemDC, hBmpOld ), ::DeleteObject( hMemBmp );
179 ::DeleteDC( hMemDC );
181 if( bDither16 )
183 // create DIBPattern for 16Bit dithering
184 long n;
186 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
187 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
188 pSalData->mpDitherDiff = new long[ 256 ];
189 pSalData->mpDitherLow = new BYTE[ 256 ];
190 pSalData->mpDitherHigh = new BYTE[ 256 ];
191 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
192 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
194 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
196 pBIH->biSize = sizeof( BITMAPINFOHEADER );
197 pBIH->biWidth = 8;
198 pBIH->biHeight = 8;
199 pBIH->biPlanes = 1;
200 pBIH->biBitCount = 24;
202 for( n = 0; n < 256L; n++ )
203 pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
205 for( n = 0; n < 256L; n++ )
206 pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
208 for( n = 0; n < 256L; n++ )
209 pSalData->mpDitherHigh[ n ] = (BYTE) std::min( pSalData->mpDitherLow[ n ] + 8L, 255L );
212 else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
214 BYTE nRed, nGreen, nBlue;
215 BYTE nR, nG, nB;
216 PALETTEENTRY* pPalEntry;
217 LOGPALETTE* pLogPal;
218 const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
219 sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
221 // create logical palette
222 pLogPal = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
223 pLogPal->palVersion = 0x0300;
224 pLogPal->palNumEntries = (sal_uInt16) nTotalCount;
225 pPalEntry = pLogPal->palPalEntry;
227 // Standard colors
228 memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
229 pPalEntry += DITHER_MAX_SYSCOLOR;
231 // own palette (6/6/6)
232 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
234 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
236 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
238 pPalEntry->peRed = nRed;
239 pPalEntry->peGreen = nGreen;
240 pPalEntry->peBlue = nBlue;
241 pPalEntry->peFlags = 0;
242 pPalEntry++;
247 // insert special 'Blue' as standard drawing color
248 *pPalEntry++ = aImplExtraColor1;
250 // create palette
251 pSalData->mhDitherPal = CreatePalette( pLogPal );
252 delete[] (char*) pLogPal;
254 if( pSalData->mhDitherPal )
256 // create DIBPattern for 8Bit dithering
257 long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
258 long n;
260 pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
261 pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
262 pSalData->mpDitherDiff = new long[ 256 ];
263 pSalData->mpDitherLow = new BYTE[ 256 ];
264 pSalData->mpDitherHigh = new BYTE[ 256 ];
265 pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
266 memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
268 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
269 short* pColors = (short*) ( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
271 pBIH->biSize = sizeof( BITMAPINFOHEADER );
272 pBIH->biWidth = 8;
273 pBIH->biHeight = 8;
274 pBIH->biPlanes = 1;
275 pBIH->biBitCount = 8;
277 for( n = 0; n < nDitherPalCount; n++ )
278 pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
280 for( n = 0; n < 256L; n++ )
281 pSalData->mpDitherDiff[ n ] = n % 51L;
283 for( n = 0; n < 256L; n++ )
284 pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
286 for( n = 0; n < 256L; n++ )
287 pSalData->mpDitherHigh[ n ] = (BYTE)std::min( pSalData->mpDitherLow[ n ] + 1, 5 );
290 // get system color entries
291 ImplUpdateSysColorEntries();
294 ReleaseDC( 0, hDC );
297 void ImplFreeSalGDI()
299 SalData* pSalData = GetSalData();
301 if (pSalData->mbResourcesAlreadyFreed)
302 return;
304 // destroy stock objects
305 int i;
306 for ( i = 0; i < pSalData->mnStockPenCount; i++ )
307 DeletePen( pSalData->mhStockPenAry[i] );
308 for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
309 DeleteBrush( pSalData->mhStockBrushAry[i] );
311 // delete 50% Brush
312 if ( pSalData->mh50Brush )
314 DeleteBrush( pSalData->mh50Brush );
315 pSalData->mh50Brush = 0;
318 // delete 50% Bitmap
319 if ( pSalData->mh50Bmp )
321 DeleteBitmap( pSalData->mh50Bmp );
322 pSalData->mh50Bmp = 0;
325 ImplClearHDCCache( pSalData );
326 delete[] pSalData->mpHDCCache;
328 // delete Ditherpalette, if existing
329 if ( pSalData->mhDitherPal )
331 DeleteObject( pSalData->mhDitherPal );
332 pSalData->mhDitherPal = 0;
335 // delete buffers for dithering DIB patterns, if necessary
336 if ( pSalData->mhDitherDIB )
338 GlobalUnlock( pSalData->mhDitherDIB );
339 GlobalFree( pSalData->mhDitherDIB );
340 pSalData->mhDitherDIB = 0;
341 delete[] pSalData->mpDitherDiff;
342 delete[] pSalData->mpDitherLow;
343 delete[] pSalData->mpDitherHigh;
346 // delete SysColorList
347 SysColorEntry* pEntry = pFirstSysColor;
348 while( pEntry )
350 SysColorEntry* pTmp = pEntry->pNext;
351 delete pEntry;
352 pEntry = pTmp;
354 pFirstSysColor = NULL;
356 // delete icon cache
357 SalIcon* pIcon = pSalData->mpFirstIcon;
358 pSalData->mpFirstIcon = NULL;
359 while( pIcon )
361 SalIcon* pTmp = pIcon->pNext;
362 DestroyIcon( pIcon->hIcon );
363 DestroyIcon( pIcon->hSmallIcon );
364 delete pIcon;
365 pIcon = pTmp;
368 // delete temporary font list
369 ImplReleaseTempFonts( *pSalData );
371 pSalData->mbResourcesAlreadyFreed = true;
374 int ImplIsSysColorEntry( SalColor nSalColor )
376 SysColorEntry* pEntry = pFirstSysColor;
377 const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
378 SALCOLOR_GREEN( nSalColor ),
379 SALCOLOR_BLUE( nSalColor ) );
381 while ( pEntry )
383 if ( pEntry->nRGB == nTestRGB )
384 return TRUE;
385 pEntry = pEntry->pNext;
388 return FALSE;
391 static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
393 // dither color?
394 if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
395 return TRUE;
397 PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
399 // standard palette color?
400 for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
402 if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
403 return TRUE;
406 // extra color?
407 if ( aImplExtraColor1.peRed == nRed &&
408 aImplExtraColor1.peGreen == nGreen &&
409 aImplExtraColor1.peBlue == nBlue )
411 return TRUE;
414 return FALSE;
417 static void ImplInsertSysColorEntry( int nSysIndex )
419 const DWORD nRGB = GetSysColor( nSysIndex );
421 if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
423 if ( !pFirstSysColor )
425 pActSysColor = pFirstSysColor = new SysColorEntry;
426 pFirstSysColor->nRGB = nRGB;
427 pFirstSysColor->pNext = NULL;
429 else
431 pActSysColor = pActSysColor->pNext = new SysColorEntry;
432 pActSysColor->nRGB = nRGB;
433 pActSysColor->pNext = NULL;
438 void ImplUpdateSysColorEntries()
440 // delete old SysColorList
441 SysColorEntry* pEntry = pFirstSysColor;
442 while( pEntry )
444 SysColorEntry* pTmp = pEntry->pNext;
445 delete pEntry;
446 pEntry = pTmp;
448 pActSysColor = pFirstSysColor = NULL;
450 // create new sys color list
451 ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
452 ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
453 ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
454 ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
455 ImplInsertSysColorEntry( COLOR_3DFACE );
456 ImplInsertSysColorEntry( COLOR_3DHILIGHT );
457 ImplInsertSysColorEntry( COLOR_3DLIGHT );
458 ImplInsertSysColorEntry( COLOR_3DSHADOW );
459 ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
460 ImplInsertSysColorEntry( COLOR_INFOBK );
461 ImplInsertSysColorEntry( COLOR_INFOTEXT );
462 ImplInsertSysColorEntry( COLOR_BTNTEXT );
463 ImplInsertSysColorEntry( COLOR_WINDOW );
464 ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
465 ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
466 ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
467 ImplInsertSysColorEntry( COLOR_MENU );
468 ImplInsertSysColorEntry( COLOR_MENUTEXT );
469 ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
470 ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
471 ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
472 ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
475 void WinSalGraphics::InitGraphics()
477 // calculate the minimal line width for the printer
478 if ( isPrinter() )
480 int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
481 if ( nDPIX <= 300 )
482 mnPenWidth = 0;
483 else
484 mnPenWidth = nDPIX/300;
487 ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
488 ::SetBkMode( getHDC(), TRANSPARENT );
489 ::SetROP2( getHDC(), R2_COPYPEN );
491 mpImpl->Init();
494 void WinSalGraphics::DeInitGraphics()
496 // clear clip region
497 SelectClipRgn( getHDC(), 0 );
498 // select default objects
499 if ( mhDefPen )
500 SelectPen( getHDC(), mhDefPen );
501 if ( mhDefBrush )
502 SelectBrush( getHDC(), mhDefBrush );
503 if ( mhDefFont )
504 SelectFont( getHDC(), mhDefFont );
506 mpImpl->DeInit();
509 HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
511 SalData* pSalData = GetSalData();
512 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
514 if( !pC->mhDC )
516 HDC hDC = GetDC( 0 );
518 // create new DC with DefaultBitmap
519 pC->mhDC = CreateCompatibleDC( hDC );
521 if( pSalData->mhDitherPal )
523 pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
524 RealizePalette( pC->mhDC );
527 pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
528 pC->mhDefBmp = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
530 ReleaseDC( 0, hDC );
533 if ( hBmp )
534 SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
535 else
536 pC->mhActBmp = 0;
538 return pC->mhDC;
541 void ImplReleaseCachedDC( sal_uLong nID )
543 SalData* pSalData = GetSalData();
544 HDCCache* pC = &pSalData->mpHDCCache[ nID ];
546 if ( pC->mhActBmp )
547 SelectObject( pC->mhDC, pC->mhSelBmp );
550 void ImplClearHDCCache( SalData* pData )
552 for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
554 HDCCache* pC = &pData->mpHDCCache[ i ];
556 if( pC->mhDC )
558 SelectObject( pC->mhDC, pC->mhDefBmp );
560 if( pC->mhDefPal )
561 SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
563 DeleteDC( pC->mhDC );
564 DeleteObject( pC->mhSelBmp );
569 OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height)
570 : mhBitmap(0)
571 , mpData(NULL)
572 , maRects(0, 0, width, height, x, y, width, height)
574 WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
575 mpImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
577 if (!mpImpl)
579 // we avoid the OpenGL drawing, instead we draw directly to the DC
580 mhCompatibleDC = rWinGraphics.getHDC();
581 return;
584 mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
586 // move the origin so that we always paint at 0,0 - to keep the bitmap
587 // small
588 OffsetViewportOrgEx(mhCompatibleDC, -x, -y, NULL);
590 mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
592 mhOrigBitmap = (HBITMAP) SelectObject(mhCompatibleDC, mhBitmap);
595 OpenGLCompatibleDC::~OpenGLCompatibleDC()
597 if (mpImpl)
599 SelectObject(mhCompatibleDC, mhOrigBitmap);
600 DeleteObject(mhBitmap);
601 DeleteDC(mhCompatibleDC);
605 void OpenGLCompatibleDC::fill(sal_uInt32 color)
607 if (!mpData)
608 return;
610 sal_uInt32 *p = mpData;
611 for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
612 *p++ = color;
615 OpenGLTexture* OpenGLCompatibleDC::getTexture()
617 if (!mpImpl)
618 return NULL;
620 // turn what's in the mpData into a texture
621 return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
624 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
625 mhLocalDC(0),
626 mbPrinter(eType == WinSalGraphics::PRINTER),
627 mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
628 mbWindow(eType == WinSalGraphics::WINDOW),
629 mhWnd(hWnd),
630 mbScreen(bScreen),
631 mfCurrentFontScale(1.0),
632 mhRegion(0),
633 mhDefPen(0),
634 mhDefBrush(0),
635 mhDefFont(0),
636 mhDefPal(0),
637 mpStdClipRgnData(NULL),
638 mpFontAttrCache(NULL),
639 mnPenWidth(GSL_PEN_WIDTH)
641 if (OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter)
642 mpImpl.reset(new WinOpenGLSalGraphicsImpl(*this, pProvider));
643 else
644 mpImpl.reset(new WinSalGraphicsImpl(*this));
646 for( int i = 0; i < MAX_FALLBACK; ++i )
648 mhFonts[ i ] = 0;
649 mpWinFontData[ i ] = NULL;
650 mpWinFontEntry[ i ] = NULL;
651 mfFontScale[ i ] = 1.0;
655 WinSalGraphics::~WinSalGraphics()
657 // free obsolete GDI objects
658 ReleaseFonts();
660 if ( mhRegion )
662 DeleteRegion( mhRegion );
663 mhRegion = 0;
666 // delete cache data
667 delete [] mpStdClipRgnData;
670 SalGraphicsImpl* WinSalGraphics::GetImpl() const
672 return mpImpl.get();
675 bool WinSalGraphics::isPrinter() const
677 return mbPrinter;
680 bool WinSalGraphics::isVirtualDevice() const
682 return mbVirDev;
685 bool WinSalGraphics::isWindow() const
687 return mbWindow;
690 bool WinSalGraphics::isScreen() const
692 return mbScreen;
695 HWND WinSalGraphics::gethWnd()
697 return mhWnd;
700 void WinSalGraphics::setHWND(HWND hWnd)
702 mhWnd = hWnd;
705 HPALETTE WinSalGraphics::getDefPal() const
707 return mhDefPal;
710 void WinSalGraphics::setDefPal(HPALETTE hDefPal)
712 mhDefPal = hDefPal;
715 HRGN WinSalGraphics::getRegion() const
717 return mhRegion;
720 void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
722 rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
723 rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
725 // #111139# this fixes the symptom of div by zero on startup
726 // however, printing will fail most likely as communication with
727 // the printer seems not to work in this case
728 if( !rDPIX || !rDPIY )
729 rDPIX = rDPIY = 600;
732 sal_uInt16 WinSalGraphics::GetBitCount() const
734 return mpImpl->GetBitCount();
737 long WinSalGraphics::GetGraphicsWidth() const
739 return mpImpl->GetGraphicsWidth();
742 void WinSalGraphics::ResetClipRegion()
744 mpImpl->ResetClipRegion();
747 bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
749 return mpImpl->setClipRegion( i_rClip );
752 void WinSalGraphics::SetLineColor()
754 mpImpl->SetLineColor();
757 void WinSalGraphics::SetLineColor( SalColor nSalColor )
759 mpImpl->SetLineColor( nSalColor );
762 void WinSalGraphics::SetFillColor()
764 mpImpl->SetFillColor();
767 void WinSalGraphics::SetFillColor( SalColor nSalColor )
769 mpImpl->SetFillColor( nSalColor );
772 void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
774 mpImpl->SetXORMode( bSet, bInvertOnly );
777 void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
779 mpImpl->SetROPLineColor( nROPColor );
782 void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
784 mpImpl->SetROPFillColor( nROPColor );
787 void WinSalGraphics::drawPixel( long nX, long nY )
789 mpImpl->drawPixel( nX, nY );
792 void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
794 mpImpl->drawPixel( nX, nY, nSalColor );
797 void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
799 mpImpl->drawLine( nX1, nY1, nX2, nY2 );
802 void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
804 mpImpl->drawRect( nX, nY, nWidth, nHeight );
807 void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry )
809 mpImpl->drawPolyLine( nPoints, pPtAry );
812 void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
814 mpImpl->drawPolygon( nPoints, pPtAry );
817 void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
818 PCONSTSALPOINT* pPtAry )
820 mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
823 bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
825 return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
828 bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
830 return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
833 bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
834 const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
836 return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
839 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize )
841 while ( nComp-- >= nSize )
843 sal_uLong i;
844 for ( i = 0; i < nSize; i++ )
846 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
847 break;
849 if ( i == nSize )
850 return pSource;
851 pSource++;
853 return NULL;
856 static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
858 bool bRetValue = FALSE;
859 BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
860 if ( pDest )
862 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
863 pDest += 14;
865 int nSizeLeft = nSize - ( pDest - pSource );
866 if ( nSizeLeft > 100 )
867 nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
869 int i;
870 for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
872 int nDivision = 1;
873 bool bDivision = FALSE;
874 bool bNegative = FALSE;
875 bool bValid = TRUE;
877 while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
878 BYTE nByte = *pDest;
879 while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
881 switch ( nByte )
883 case '.' :
884 if ( bDivision )
885 bValid = FALSE;
886 else
887 bDivision = TRUE;
888 break;
889 case '-' :
890 bNegative = TRUE;
891 break;
892 default :
893 if ( ( nByte < '0' ) || ( nByte > '9' ) )
894 nSizeLeft = 1; // error parsing the bounding box values
895 else if ( bValid )
897 if ( bDivision )
898 nDivision*=10;
899 nNumb[i] *= 10;
900 nNumb[i] += nByte - '0';
902 break;
904 nSizeLeft--;
905 nByte = *(++pDest);
907 if ( bNegative )
908 nNumb[i] = -nNumb[i];
909 if ( bDivision && ( nDivision != 1 ) )
910 nNumb[i] /= nDivision;
912 if ( i == 4 )
913 bRetValue = TRUE;
915 return bRetValue;
918 #define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
920 bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
922 bool bRetValue = false;
924 if ( mbPrinter )
926 int nEscape = POSTSCRIPT_PASSTHROUGH;
928 if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
930 double nBoundingBox[4];
932 if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
934 OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
936 // reserve place for a sal_uInt16
937 aBuf.append( "aa" );
939 // #107797# Write out EPS encapsulation header
941 // directly taken from the PLRM 3.0, p. 726. Note:
942 // this will definitely cause problems when
943 // recursively creating and embedding PostScript files
944 // in OOo, since we use statically-named variables
945 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
946 // op_count_salWin). Currently, I have no idea on how to
947 // work around that, except from scanning and
948 // interpreting the EPS for unused identifiers.
950 // append the real text
951 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
952 "/dict_count_salWin countdictstack def\n"
953 "/op_count_salWin count 1 sub def\n"
954 "userdict begin\n"
955 "/showpage {} def\n"
956 "0 setgray 0 setlinecap\n"
957 "1 setlinewidth 0 setlinejoin\n"
958 "10 setmiterlimit [] 0 setdash newpath\n"
959 "/languagelevel where\n"
960 "{\n"
961 " pop languagelevel\n"
962 " 1 ne\n"
963 " {\n"
964 " false setstrokeadjust false setoverprint\n"
965 " } if\n"
966 "} if\n\n" );
968 // #i10737# Apply clipping manually
970 // Windows seems to ignore any clipping at the HDC,
971 // when followed by a POSTSCRIPT_PASSTHROUGH
973 // Check whether we've got a clipping, consisting of
974 // exactly one rect (other cases should be, but aren't
975 // handled currently)
977 // TODO: Handle more than one rectangle here (take
978 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
979 // characters!)
980 if ( mhRegion != 0 &&
981 mpStdClipRgnData != NULL &&
982 mpClipRgnData == mpStdClipRgnData &&
983 mpClipRgnData->rdh.nCount == 1 )
985 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
987 aBuf.append( "\nnewpath\n" );
988 aBuf.append( pRect->left );
989 aBuf.append( " " );
990 aBuf.append( pRect->top );
991 aBuf.append( " moveto\n" );
992 aBuf.append( pRect->right );
993 aBuf.append( " " );
994 aBuf.append( pRect->top );
995 aBuf.append( " lineto\n" );
996 aBuf.append( pRect->right );
997 aBuf.append( " " );
998 aBuf.append( pRect->bottom );
999 aBuf.append( " lineto\n" );
1000 aBuf.append( pRect->left );
1001 aBuf.append( " " );
1002 aBuf.append( pRect->bottom );
1003 aBuf.append( " lineto\n"
1004 "closepath\n"
1005 "clip\n"
1006 "newpath\n" );
1009 // #107797# Write out buffer
1011 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1012 Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1014 // #107797# Write out EPS transformation code
1016 double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
1017 double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
1018 // reserve a sal_uInt16 again
1019 aBuf.setLength( 2 );
1020 aBuf.append( "\n\n[" );
1021 aBuf.append( dM11 );
1022 aBuf.append( " 0 0 " );
1023 aBuf.append( dM22 );
1024 aBuf.append( ' ' );
1025 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
1026 aBuf.append( ' ' );
1027 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
1028 aBuf.append( "] concat\n"
1029 "%%BeginDocument:\n" );
1030 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1031 Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1033 // #107797# Write out actual EPS content
1035 sal_uLong nToDo = nSize;
1036 sal_uLong nDoNow;
1037 while ( nToDo )
1039 nDoNow = nToDo;
1040 if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
1041 nDoNow = POSTSCRIPT_BUFSIZE - 2;
1042 // the following is based on the string buffer allocation
1043 // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
1044 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
1045 memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
1046 sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
1047 if (!nResult )
1048 break;
1049 nToDo -= nResult;
1052 // #107797# Write out EPS encapsulation footer
1054 // reserve a sal_uInt16 again
1055 aBuf.setLength( 2 );
1056 aBuf.append( "%%EndDocument\n"
1057 "count op_count_salWin sub {pop} repeat\n"
1058 "countdictstack dict_count_salWin sub {end} repeat\n"
1059 "b4_Inc_state_salWin restore\n\n" );
1060 *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
1061 Escape ( getHDC(), nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
1062 bRetValue = TRUE;
1067 return bRetValue;
1070 SystemGraphicsData WinSalGraphics::GetGraphicsData() const
1072 SystemGraphicsData aRes;
1073 aRes.nSize = sizeof(aRes);
1074 aRes.hDC = const_cast< WinSalGraphics* >(this)->getHDC();
1075 return aRes;
1078 bool WinSalGraphics::SupportsCairo() const
1080 #if ENABLE_CAIRO_CANVAS
1081 return true;
1082 #else
1083 return false;
1084 #endif
1088 * cairo::createSurface: Create generic Canvas surface using given Cairo Surface
1090 * @param rSurface Cairo Surface
1092 * @return new Surface
1094 cairo::SurfaceSharedPtr WinSalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const
1096 #if ENABLE_CAIRO_CANVAS
1097 return cairo::SurfaceSharedPtr(new cairo::Win32Surface(rSurface));
1098 #else
1099 (void)rSurface;
1100 return cairo::SurfaceSharedPtr();
1101 #endif
1105 * cairo::createSurface: Create Canvas surface using given VCL Window or Virtualdevice
1107 * @param rSurface Cairo Surface
1109 * For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
1110 * For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx)
1112 * @return new Surface
1114 cairo::SurfaceSharedPtr WinSalGraphics::CreateSurface( const OutputDevice& rRefDevice,
1115 int x, int y, int /* width */, int /* height */) const
1117 cairo::SurfaceSharedPtr surf;
1119 #if ENABLE_CAIRO_CANVAS
1120 if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
1122 const vcl::Window &rWindow = (const vcl::Window &) rRefDevice;
1123 const SystemEnvData* pSysData = GetSysData(&rWindow);
1124 if (pSysData && pSysData->hWnd)
1125 surf = cairo::SurfaceSharedPtr(new cairo::Win32Surface(GetDC((HWND) pSysData->hWnd), x, y));
1127 else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
1129 SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData();
1130 if (aSysData.hDC)
1131 surf = cairo::SurfaceSharedPtr(new cairo::Win32Surface((HDC) aSysData.hDC, x, y));
1133 #else
1134 (void)rRefDevice;
1135 (void)x;
1136 (void)y;
1137 #endif
1139 return surf;
1143 * cairo::createBitmapSurface: Create platform native Canvas surface from BitmapSystemData
1144 * @param OutputDevice (not used)
1145 * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
1146 * @param rSize width and height of the new surface
1148 * Create a surface based on image data on rData
1150 * @return new surface or empty surface
1152 cairo::SurfaceSharedPtr WinSalGraphics::CreateBitmapSurface( const OutputDevice& /* rRefDevice */,
1153 const BitmapSystemData& rData,
1154 const Size& rSize ) const
1156 OSL_TRACE( "requested size: %d x %d available size: %d x %d",
1157 rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight );
1159 #if ENABLE_CAIRO_CANVAS
1160 if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
1161 return cairo::SurfaceSharedPtr(new cairo::Win32Surface( rData ));
1162 #else
1163 (void)rData;
1164 (void)rSize;
1165 #endif
1166 return cairo::SurfaceSharedPtr();
1169 #if ENABLE_CAIRO_CANVAS
1170 namespace
1172 HBITMAP surface2HBitmap( const SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize )
1174 // can't seem to retrieve HBITMAP from cairo. copy content then
1175 HDC hScreenDC=GetDC(NULL);
1176 HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC,
1177 rSize.getX(),
1178 rSize.getY() );
1180 HDC hBmpDC = CreateCompatibleDC( 0 );
1181 HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hBmpBitmap );
1183 BitBlt( hBmpDC, 0, 0, rSize.getX(), rSize.getX(),
1184 cairo_win32_surface_get_dc(rSurface->getCairoSurface().get()),
1185 0, 0, SRCCOPY );
1187 SelectObject( hBmpDC, hBmpOld );
1188 DeleteDC( hBmpDC );
1190 return hBmpBitmap;
1193 #endif
1195 css::uno::Any WinSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const ::basegfx::B2ISize& rSize) const
1197 // TODO(F2): check whether under all circumstances,
1198 // the alpha channel is ignored here.
1199 css::uno::Sequence< css::uno::Any > args( 1 );
1200 sal_Int64 nHandle;
1201 #if ENABLE_CAIRO_CANVAS
1202 nHandle = sal_Int64(surface2HBitmap(rSurface, rSize));
1203 #else
1204 (void)rSurface;
1205 (void)rSize;
1206 nHandle = 0;
1207 #endif
1208 args[1] = css::uno::Any(nHandle);
1209 // caller frees the bitmap
1210 return css::uno::Any( args );
1213 OpenGLContext *WinSalGraphics::BeginPaint()
1215 return mpImpl->beginPaint();
1218 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */