From d6f58fd25eeca84a94528409a05b80aa5172b8b8 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 Conflicts: vcl/source/gdi/gdimtf.cxx --- canvas/source/cairo/cairo_canvasbitmap.cxx | 133 +++++++++++++++-------------- vcl/inc/vcl/bitmapex.hxx | 11 +++ vcl/source/gdi/bitmapex.cxx | 78 ++++++++++++++++- vcl/source/gdi/gdimtf.cxx | 35 ++------ 4 files changed, 163 insertions(+), 94 deletions(-) diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx b/canvas/source/cairo/cairo_canvasbitmap.cxx index 91f61940dc1d..062af840b595 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->SetPixel( y, x, BitmapColor( 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; } } diff --git a/vcl/inc/vcl/bitmapex.hxx b/vcl/inc/vcl/bitmapex.hxx index 9eaaf618200c..d0c1f98a8904 100644 --- a/vcl/inc/vcl/bitmapex.hxx +++ b/vcl/inc/vcl/bitmapex.hxx @@ -25,6 +25,12 @@ #include #include +#include + +namespace com { namespace sun { namespace star { namespace rendering { + class XBitmapCanvas; +} } } } + // ------------------- // - TransparentType - // ------------------- @@ -382,6 +388,11 @@ public: friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx ); friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx ); static BitmapEx AutoScaleBitmap(BitmapEx & aBitmap, const long aStandardSize); + + /// populate from a canvas implementation + bool Create( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas > &xBitmapCanvas, + const Size &rSize ); }; #endif // _SV_BITMAPEX_HXX diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index 45fe0aa925ec..59fc06a503ed 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -17,7 +17,6 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ - #include #include @@ -39,6 +38,13 @@ #include #include +// BitmapEx::Create +#include +#include +#include +#include +using namespace ::com::sun::star; + BitmapEx::BitmapEx() : eTransparent( TRANSPARENT_NONE ), bAlpha ( sal_False ) @@ -856,4 +862,74 @@ SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx ) return rIStm; } +// Shift alpha transparent pixels between cppcanvas/ implementations +// and vcl in a generally grotesque and under-performing fashion +bool BitmapEx::Create( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas > &xBitmapCanvas, + const Size &rSize ) +{ + SetEmpty(); + Size aSize( rSize ); + + uno::Reference< beans::XFastPropertySet > xFastPropertySet( xBitmapCanvas, uno::UNO_QUERY ); + if( xFastPropertySet.get() ) + { + // 0 means get BitmapEx + uno::Any aAny = xFastPropertySet->getFastPropertyValue( 0 ); + BitmapEx* pBitmapEx = (BitmapEx*) *reinterpret_cast(aAny.getValue()); + if( pBitmapEx ) + { + *this = *pBitmapEx; + delete pBitmapEx; + return true; + } + } + + SalBitmap* pSalBmp, *pSalMask; + + pSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap(); + pSalMask = ImplGetSVData()->mpDefInst->CreateSalBitmap(); + + if( pSalBmp->Create( xBitmapCanvas, aSize ) ) + { +#ifdef CLAMP_BITDEPTH_PARANOIA + // did we get alpha mixed up in the bitmap itself + // eg. Cairo Canvas ... yes performance of this is awful. + if( pSalBmp->GetBitCount() > 24 ) + { + // Format convert the pixels with generic code + Bitmap aSrcPixels( pSalBmp ); + aBitmap = Bitmap( rSize, 24 ); + BitmapReadAccess aSrcRead( aSrcPixels ); + BitmapWriteAccess aDestWrite( aBitmap ); + aDestWrite.CopyBuffer( aSrcRead ); + } + else +#endif + aBitmap = Bitmap( pSalBmp ); + + aBitmapSize = rSize; + if ( pSalMask->Create( xBitmapCanvas, aSize, true ) ) + { + aMask = Bitmap( pSalMask ); + bAlpha = sal_True; + aBitmapSize = rSize; + eTransparent = !aMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP; + + return true; + } + else + { + bAlpha = sal_False; + eTransparent = TRANSPARENT_NONE; + return true; + } + } + + delete pSalBmp; + delete pSalMask; + + return false; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index 33e304bbc150..f43b6ca4f6b2 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -487,35 +487,16 @@ bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, S xMtfFastPropertySet->setFastPropertyValue( 0, uno::Any( reinterpret_cast( this ) ) ); xMtfRenderer->draw( rDestSize.Width(), rDestSize.Height() ); + } - uno::Reference< beans::XFastPropertySet > xFastPropertySet( xBitmapCanvas, uno::UNO_QUERY ); - if( xFastPropertySet.get() ) - { - // 0 means get BitmapEx - uno::Any aAny = xFastPropertySet->getFastPropertyValue( 0 ); - BitmapEx* pBitmapEx = (BitmapEx*) *reinterpret_cast(aAny.getValue()); - if( pBitmapEx ) { - pOut->DrawBitmapEx( rPos, rLogicDestSize, *pBitmapEx ); - delete pBitmapEx; - return true; - } - } - - SalBitmap* pSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap(); - SalBitmap* pSalMask = ImplGetSVData()->mpDefInst->CreateSalBitmap(); - - if( pSalBmp->Create( xBitmapCanvas, aSize ) && pSalMask->Create( xBitmapCanvas, aSize, true ) ) - { - Bitmap aBitmap( pSalBmp ); - Bitmap aMask( pSalMask ); - AlphaMask aAlphaMask( aMask ); - BitmapEx aBitmapEx( aBitmap, aAlphaMask ); + BitmapEx aBitmapEx; + if( aBitmapEx.Create( xBitmapCanvas, aSize ) ) + { + if ( pOut->GetMapMode() == MAP_PIXEL ) pOut->DrawBitmapEx( rPos, aBitmapEx ); - return true; - } - - delete pSalBmp; - delete pSalMask; + else + pOut->DrawBitmapEx( rPos, rLogicDestSize, aBitmapEx ); + return true; } } } -- cgit v1.2.3