Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / directx / dx_vcltools.cxx
blob727008049e68ae4c387a456d09fba71d11c2111f
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 .
21 #include <vcl/canvastools.hxx>
23 #include <vcl/bitmap.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/bmpacc.hxx>
26 #include <tools/diagnose_ex.h>
28 #include "dx_impltools.hxx"
29 #include <basegfx/numeric/ftools.hxx>
31 #include <canvas/debug.hxx>
32 #include <canvas/verbosetrace.hxx>
34 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
37 #include <boost/scoped_array.hpp>
39 #include "dx_vcltools.hxx"
41 using namespace ::com::sun::star;
43 namespace dxcanvas
45 namespace tools
47 namespace
49 /// Calc number of colors in given BitmapInfoHeader
50 sal_Int32 calcDIBColorCount( const BITMAPINFOHEADER& rBIH )
52 if( rBIH.biSize != sizeof( BITMAPCOREHEADER ) )
54 if( rBIH.biBitCount <= 8 )
56 if( rBIH.biClrUsed )
57 return rBIH.biClrUsed;
58 else
59 return 1L << rBIH.biBitCount;
62 else
64 BITMAPCOREHEADER* pCoreHeader = (BITMAPCOREHEADER*)&rBIH;
66 if( pCoreHeader->bcBitCount <= 8 )
67 return 1L << pCoreHeader->bcBitCount;
70 return 0; // nothing known
73 /// Draw DI bits to given Graphics
74 bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics,
75 const void* hDIB )
77 bool bRet( false );
78 BitmapSharedPtr pBitmap;
80 const BITMAPINFO* pBI = (BITMAPINFO*)GlobalLock( (HGLOBAL)hDIB );
82 if( pBI )
84 const BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*)pBI;
85 const BYTE* pBits = (BYTE*) pBI + *(DWORD*)pBI +
86 calcDIBColorCount( *pBIH ) * sizeof( RGBQUAD );
88 // forward to outsourced GDI+ rendering method
89 // (header clashes)
90 bRet = tools::drawDIBits( rGraphics, *pBI, (void*)pBits );
92 GlobalUnlock( (HGLOBAL)hDIB );
95 return bRet;
98 /** Draw VCL bitmap to given Graphics
100 @param rBmp
101 Reference to bitmap. Might get modified, in such a way
102 that it will hold a DIB after a successful function call.
104 bool drawVCLBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics,
105 ::Bitmap& rBmp )
107 BitmapSystemData aBmpSysData;
109 if( !rBmp.GetSystemData( aBmpSysData ) ||
110 !aBmpSysData.pDIB )
112 // first of all, ensure that Bitmap contains a DIB, by
113 // acquiring a read access
114 BitmapReadAccess* pReadAcc = rBmp.AcquireReadAccess();
116 // TODO(P2): Acquiring a read access can actually
117 // force a read from VRAM, thus, avoiding this
118 // step somehow will increase performance
119 // here.
120 if( pReadAcc )
122 // try again: now, WinSalBitmap must have
123 // generated a DIB
124 if( rBmp.GetSystemData( aBmpSysData ) &&
125 aBmpSysData.pDIB )
127 return drawDIBits( rGraphics,
128 aBmpSysData.pDIB );
131 rBmp.ReleaseAccess( pReadAcc );
134 else
136 return drawDIBits( rGraphics,
137 aBmpSysData.pDIB );
140 // failed to generate DIBits from vcl bitmap
141 return false;
144 /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX
146 RawRGBABitmap bitmapFromVCLBitmapEx( const ::BitmapEx& rBmpEx )
148 // TODO(P2): Avoid temporary bitmap generation, maybe
149 // even ensure that created DIBs are copied back to
150 // BmpEx (currently, every AcquireReadAccess() will
151 // make the local bitmap copy unique, effectively
152 // duplicating the memory used)
154 ENSURE_OR_THROW( rBmpEx.IsTransparent(),
155 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
156 "BmpEx not transparent" );
158 // convert transparent bitmap to 32bit RGBA
159 // ========================================
161 const ::Size aBmpSize( rBmpEx.GetSizePixel() );
163 RawRGBABitmap aBmpData;
164 aBmpData.mnWidth = aBmpSize.Width();
165 aBmpData.mnHeight = aBmpSize.Height();
166 aBmpData.mpBitmapData.reset( new sal_uInt8[ 4*aBmpData.mnWidth*aBmpData.mnHeight ] );
168 Bitmap aBitmap( rBmpEx.GetBitmap() );
170 Bitmap::ScopedReadAccess pReadAccess( aBitmap );
172 const sal_Int32 nWidth( aBmpSize.Width() );
173 const sal_Int32 nHeight( aBmpSize.Height() );
175 ENSURE_OR_THROW( pReadAccess.get() != NULL,
176 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
177 "Unable to acquire read access to bitmap" );
179 if( rBmpEx.IsAlpha() )
181 Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() );
183 Bitmap::ScopedReadAccess pAlphaReadAccess( aAlpha );
185 // By convention, the access buffer always has
186 // one of the following formats:
188 // BMP_FORMAT_1BIT_MSB_PAL
189 // BMP_FORMAT_4BIT_MSN_PAL
190 // BMP_FORMAT_8BIT_PAL
191 // BMP_FORMAT_16BIT_TC_LSB_MASK
192 // BMP_FORMAT_24BIT_TC_BGR
193 // BMP_FORMAT_32BIT_TC_MASK
195 // and is always BMP_FORMAT_BOTTOM_UP
197 // This is the way
198 // WinSalBitmap::AcquireBuffer() sets up the
199 // buffer
201 ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL,
202 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
203 "Unable to acquire read access to alpha" );
205 ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
206 pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
207 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
208 "Unsupported alpha scanline format" );
210 BitmapColor aCol;
211 const sal_Int32 nWidth( aBmpSize.Width() );
212 const sal_Int32 nHeight( aBmpSize.Height() );
213 sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() );
214 int x, y;
216 for( y=0; y<nHeight; ++y )
218 switch( pReadAccess->GetScanlineFormat() )
220 case BMP_FORMAT_8BIT_PAL:
222 Scanline pScan = pReadAccess->GetScanline( y );
223 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
225 for( x=0; x<nWidth; ++x )
227 aCol = pReadAccess->GetPaletteColor( *pScan++ );
229 *pCurrOutput++ = aCol.GetBlue();
230 *pCurrOutput++ = aCol.GetGreen();
231 *pCurrOutput++ = aCol.GetRed();
233 // out notion of alpha is
234 // different from the rest
235 // of the world's
236 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
239 break;
241 case BMP_FORMAT_24BIT_TC_BGR:
243 Scanline pScan = pReadAccess->GetScanline( y );
244 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
246 for( x=0; x<nWidth; ++x )
248 // store as RGBA
249 *pCurrOutput++ = *pScan++;
250 *pCurrOutput++ = *pScan++;
251 *pCurrOutput++ = *pScan++;
253 // out notion of alpha is
254 // different from the rest
255 // of the world's
256 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
259 break;
261 // TODO(P2): Might be advantageous
262 // to hand-formulate the following
263 // formats, too.
264 case BMP_FORMAT_1BIT_MSB_PAL:
265 // FALLTHROUGH intended
266 case BMP_FORMAT_4BIT_MSN_PAL:
267 // FALLTHROUGH intended
268 case BMP_FORMAT_16BIT_TC_LSB_MASK:
269 // FALLTHROUGH intended
270 case BMP_FORMAT_32BIT_TC_MASK:
272 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
274 // using fallback for those
275 // seldom formats
276 for( x=0; x<nWidth; ++x )
278 // yes. x and y are swapped on Get/SetPixel
279 aCol = pReadAccess->GetColor(y,x);
281 *pCurrOutput++ = aCol.GetBlue();
282 *pCurrOutput++ = aCol.GetGreen();
283 *pCurrOutput++ = aCol.GetRed();
285 // out notion of alpha is
286 // different from the rest
287 // of the world's
288 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
291 break;
293 case BMP_FORMAT_1BIT_LSB_PAL:
294 // FALLTHROUGH intended
295 case BMP_FORMAT_4BIT_LSN_PAL:
296 // FALLTHROUGH intended
297 case BMP_FORMAT_8BIT_TC_MASK:
298 // FALLTHROUGH intended
299 case BMP_FORMAT_24BIT_TC_RGB:
300 // FALLTHROUGH intended
301 case BMP_FORMAT_24BIT_TC_MASK:
302 // FALLTHROUGH intended
303 case BMP_FORMAT_16BIT_TC_MSB_MASK:
304 // FALLTHROUGH intended
305 case BMP_FORMAT_32BIT_TC_ABGR:
306 // FALLTHROUGH intended
307 case BMP_FORMAT_32BIT_TC_ARGB:
308 // FALLTHROUGH intended
309 case BMP_FORMAT_32BIT_TC_BGRA:
310 // FALLTHROUGH intended
311 case BMP_FORMAT_32BIT_TC_RGBA:
312 // FALLTHROUGH intended
313 default:
314 ENSURE_OR_THROW( false,
315 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
316 "Unexpected scanline format - has "
317 "WinSalBitmap::AcquireBuffer() changed?" );
321 else
323 Bitmap aMask( rBmpEx.GetMask() );
325 Bitmap::ScopedReadAccess pMaskReadAccess( aMask );
327 // By convention, the access buffer always has
328 // one of the following formats:
330 // BMP_FORMAT_1BIT_MSB_PAL
331 // BMP_FORMAT_4BIT_MSN_PAL
332 // BMP_FORMAT_8BIT_PAL
333 // BMP_FORMAT_16BIT_TC_LSB_MASK
334 // BMP_FORMAT_24BIT_TC_BGR
335 // BMP_FORMAT_32BIT_TC_MASK
337 // and is always BMP_FORMAT_BOTTOM_UP
339 // This is the way
340 // WinSalBitmap::AcquireBuffer() sets up the
341 // buffer
343 ENSURE_OR_THROW( pMaskReadAccess.get() != NULL,
344 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
345 "Unable to acquire read access to mask" );
347 ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL,
348 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
349 "Unsupported mask scanline format" );
351 BitmapColor aCol;
352 int nCurrBit;
353 const int nMask( 1L );
354 const int nInitialBit(7);
355 sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() );
356 int x, y;
358 // mapping table, to get from mask index color to
359 // alpha value (which depends on the mask's palette)
360 sal_uInt8 aColorMap[2];
362 const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) );
363 const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) );
365 // shortcut for true luminance calculation
366 // (assumes that palette is grey-level). Note the
367 // swapped the indices here, to account for the
368 // fact that VCL's notion of alpha is inverted to
369 // the rest of the world's.
370 aColorMap[0] = rCol1.GetRed();
371 aColorMap[1] = rCol0.GetRed();
373 for( y=0; y<nHeight; ++y )
375 switch( pReadAccess->GetScanlineFormat() )
377 case BMP_FORMAT_8BIT_PAL:
379 Scanline pScan = pReadAccess->GetScanline( y );
380 Scanline pMScan = pMaskReadAccess->GetScanline( y );
382 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
384 aCol = pReadAccess->GetPaletteColor( *pScan++ );
386 *pCurrOutput++ = aCol.GetBlue();
387 *pCurrOutput++ = aCol.GetGreen();
388 *pCurrOutput++ = aCol.GetRed();
390 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ];
391 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
394 break;
396 case BMP_FORMAT_24BIT_TC_BGR:
398 Scanline pScan = pReadAccess->GetScanline( y );
399 Scanline pMScan = pMaskReadAccess->GetScanline( y );
401 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
403 // store as RGBA
404 *pCurrOutput++ = *pScan++;
405 *pCurrOutput++ = *pScan++;
406 *pCurrOutput++ = *pScan++;
408 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ];
409 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
412 break;
414 // TODO(P2): Might be advantageous
415 // to hand-formulate the following
416 // formats, too.
417 case BMP_FORMAT_1BIT_MSB_PAL:
418 // FALLTHROUGH intended
419 case BMP_FORMAT_4BIT_MSN_PAL:
420 // FALLTHROUGH intended
421 case BMP_FORMAT_16BIT_TC_LSB_MASK:
422 // FALLTHROUGH intended
423 case BMP_FORMAT_32BIT_TC_MASK:
425 Scanline pMScan = pMaskReadAccess->GetScanline( y );
427 // using fallback for those
428 // seldom formats
429 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
431 // yes. x and y are swapped on Get/SetPixel
432 aCol = pReadAccess->GetColor(y,x);
434 // store as RGBA
435 *pCurrOutput++ = aCol.GetBlue();
436 *pCurrOutput++ = aCol.GetGreen();
437 *pCurrOutput++ = aCol.GetRed();
439 *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ];
440 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
443 break;
445 case BMP_FORMAT_1BIT_LSB_PAL:
446 // FALLTHROUGH intended
447 case BMP_FORMAT_4BIT_LSN_PAL:
448 // FALLTHROUGH intended
449 case BMP_FORMAT_8BIT_TC_MASK:
450 // FALLTHROUGH intended
451 case BMP_FORMAT_24BIT_TC_RGB:
452 // FALLTHROUGH intended
453 case BMP_FORMAT_24BIT_TC_MASK:
454 // FALLTHROUGH intended
455 case BMP_FORMAT_16BIT_TC_MSB_MASK:
456 // FALLTHROUGH intended
457 case BMP_FORMAT_32BIT_TC_ABGR:
458 // FALLTHROUGH intended
459 case BMP_FORMAT_32BIT_TC_ARGB:
460 // FALLTHROUGH intended
461 case BMP_FORMAT_32BIT_TC_BGRA:
462 // FALLTHROUGH intended
463 case BMP_FORMAT_32BIT_TC_RGBA:
464 // FALLTHROUGH intended
465 default:
466 ENSURE_OR_THROW( false,
467 "::dxcanvas::tools::bitmapFromVCLBitmapEx(): "
468 "Unexpected scanline format - has "
469 "WinSalBitmap::AcquireBuffer() changed?" );
474 return aBmpData;
477 bool drawVCLBitmapEx( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics,
478 const ::BitmapEx& rBmpEx )
480 if( !rBmpEx.IsTransparent() )
482 Bitmap aBmp( rBmpEx.GetBitmap() );
483 return drawVCLBitmap( rGraphics, aBmp );
485 else
487 return drawRGBABits( rGraphics,
488 bitmapFromVCLBitmapEx( rBmpEx ) );
493 bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics,
494 const uno::Reference< rendering::XBitmap >& xBitmap )
496 // TODO(F2): add support for floating point bitmap formats
497 uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp(
498 xBitmap, uno::UNO_QUERY );
500 if( !xIntBmp.is() )
501 return false;
503 ::BitmapEx aBmpEx = vcl::unotools::bitmapExFromXBitmap( xIntBmp );
504 if( !aBmpEx )
505 return false;
507 return drawVCLBitmapEx( rGraphics, aBmpEx );
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */