From 7cf2b5809f7137acc7a5eed9159042b3d748da01 Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Mon, 10 Jun 2013 17:02:06 +0100 Subject: Cairo canvas fixes + Move BitmapEx construction from an XBitmapCanvas into BitmapEx where (arguably) it will be easier to re-factor later, treat a mask fetch failure as if we have no mask + Teach the cairo canvas to return a non-pre-multiplied RGB + separate Alpha BitmapEx when it can to avoid unpleasantness with the underlying X resources. + Add tentative code-path to convert 32bit color Bitmaps into 24bit color, to avoid confusing X Change-Id: Iaf6998c796aea6d73c57bed2bc03152d9636d5f5 --- canvas/source/cairo/cairo_canvasbitmap.cxx | 133 +++++++++++++++-------------- 1 file changed, 67 insertions(+), 66 deletions(-) (limited to 'canvas/source') diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx b/canvas/source/cairo/cairo_canvasbitmap.cxx index 91f61940dc1d..496b5cfe794d 100644 --- a/canvas/source/cairo/cairo_canvasbitmap.cxx +++ b/canvas/source/cairo/cairo_canvasbitmap.cxx @@ -23,6 +23,9 @@ #include "cairo_canvasbitmap.hxx" +#include +#include + #ifdef CAIRO_HAS_XLIB_SURFACE # include "cairo_xlib_cairo.hxx" #elif defined CAIRO_HAS_QUARTZ_SURFACE @@ -144,7 +147,67 @@ namespace cairocanvas { case 0: { - aRV = uno::Any( reinterpret_cast( (BitmapEx*) NULL ) ); + aRV = uno::Any( reinterpret_cast( (BitmapEx *) NULL ) ); + if ( !mbHasAlpha ) + break; + + ::Size aSize( maSize.getX(), maSize.getY() ); + // FIXME: if we could teach VCL/ about cairo handles, life could + // be significantly better here perhaps. + cairo_surface_t *pPixels; + pPixels = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, + aSize.Width(), aSize.Height() ); + cairo_t *pCairo = cairo_create( pPixels ); + if( !pPixels || !pCairo ) + break; + + // suck ourselves from the X server to this buffer so then we can fiddle with + // Alpha to turn it into the ultra-lame vcl required format and then push it + // all back again later at vast expense [ urgh ] + cairo_set_source_surface( pCairo, getSurface()->getCairoSurface().get(), 0, 0 ); + cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE ); + cairo_paint( pCairo ); + + ::Bitmap aRGB( aSize, 24 ); + ::AlphaMask aMask( aSize ); + + BitmapWriteAccess *pRGBWrite( aRGB.AcquireWriteAccess() ); + BitmapWriteAccess *pMaskWrite( aMask.AcquireWriteAccess() ); + + unsigned char *pSrc = cairo_image_surface_get_data( pPixels ); + unsigned int nStride = cairo_image_surface_get_stride( pPixels ); + for( unsigned long y = 0; y < (unsigned long) aSize.Height(); y++ ) + { + sal_uInt32 *pPix = (sal_uInt32 *)(pSrc + nStride * y); + for( unsigned long x = 0; x < (unsigned long) aSize.Width(); x++ ) + { + sal_uInt8 nAlpha = (*pPix >> 24); + sal_uInt8 nR = (*pPix >> 16) & 0xff; + sal_uInt8 nG = (*pPix >> 8) & 0xff; + sal_uInt8 nB = *pPix & 0xff; + if( nAlpha != 0 && nAlpha != 255 ) + { +// fprintf (stderr, "From A(0x%.2x) 0x%.2x 0x%.2x 0x%.2x -> ", +// nAlpha, nR, nG, nB ); + // Cairo uses pre-multiplied alpha - we do not => re-multiply + nR = (sal_uInt8) MinMax( ((sal_uInt32)nR * 255) / nAlpha, 0, 255 ); + nG = (sal_uInt8) MinMax( ((sal_uInt32)nG * 255) / nAlpha, 0, 255 ); + nB = (sal_uInt8) MinMax( ((sal_uInt32)nB * 255) / nAlpha, 0, 255 ); +// fprintf (stderr, "0x%.2x 0x%.2x 0x%.2x\n", nR, nG, nB ); + } + pRGBWrite->SetPixel( y, x, BitmapColor( nR, nG, nB ) ); + pMaskWrite->SetPixelIndex( y, x, 255 - nAlpha ); + pPix++; + } + } + aMask.ReleaseAccess( pMaskWrite ); + aRGB.ReleaseAccess( pRGBWrite ); + + ::BitmapEx *pBitmapEx = new ::BitmapEx( aRGB, aMask ); + + cairo_surface_destroy( pPixels ); + + aRV = uno::Any( reinterpret_cast( pBitmapEx ) ); break; } case 1: @@ -179,71 +242,9 @@ namespace cairocanvas } case 2: { -#ifdef CAIRO_HAS_XLIB_SURFACE - uno::Sequence< uno::Any > args( 3 ); - SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); - CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); - X11Surface* pXlibSurface=dynamic_cast(pAlphaSurface.get()); - OSL_ASSERT(pXlibSurface); - - // create RGB image (levels of gray) of alpha channel of original picture - cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); - cairo_paint( pAlphaCairo.get() ); - cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); - cairo_paint( pAlphaCairo.get() ); - pAlphaCairo.reset(); - - X11PixmapSharedPtr pPixmap = pXlibSurface->getPixmap(); - args[0] = uno::Any( true ); - args[1] = ::com::sun::star::uno::Any( pPixmap->mhDrawable ); - args[2] = ::com::sun::star::uno::Any( sal_Int32( pXlibSurface->getDepth () ) ); - pPixmap->clear(); // caller takes ownership of pixmap - - // return pixmap and alphachannel pixmap - it will be used in BitmapEx - aRV = uno::Any( args ); -#elif defined CAIRO_HAS_QUARTZ_SURFACE - SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); - CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); - QuartzSurface* pQuartzSurface=dynamic_cast(pAlphaSurface.get()); - OSL_ASSERT(pQuartzSurface); - - // create RGB image (levels of gray) of alpha channel of original picture - cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); - cairo_paint( pAlphaCairo.get() ); - cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); - cairo_paint( pAlphaCairo.get() ); - pAlphaCairo.reset(); - - uno::Sequence< uno::Any > args( 1 ); - args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) ); - // return ??? and alphachannel ??? - it will be used in BitmapEx - aRV = uno::Any( args ); -#elif defined CAIRO_HAS_WIN32_SURFACE - SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); - CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); - - // create RGB image (levels of gray) of alpha channel of original picture - cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); - cairo_paint( pAlphaCairo.get() ); - cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); - cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); - cairo_paint( pAlphaCairo.get() ); - pAlphaCairo.reset(); - - // cant seem to retrieve HBITMAP from cairo. copy content then - uno::Sequence< uno::Any > args( 1 ); - args[1] = uno::Any( sal_Int64(surface2HBitmap(pAlphaSurface,maSize)) ); - - aRV = uno::Any( args ); - // caller frees the bitmap -#else -# error Please define fast prop retrieval for your platform! -#endif + // Always return nothing - for the RGB surface support. + // Alpha code paths go via the above case 0. + aRV = uno::Any(); break; } } -- cgit