summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@suse.com>2013-06-10 17:02:06 +0100
committerPetr Mladek <pmladek@suse.cz>2013-06-12 15:15:36 +0200
commit12d9559a5498d1c73b3bd8f130a416a029ceaf15 (patch)
treea2b22878c9993c579681b54ded2359c6aba04fd9
parent7c04d6136fd34c15003f4d42f417e4f317772777 (diff)
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
-rw-r--r--canvas/source/cairo/cairo_canvasbitmap.cxx133
-rw-r--r--vcl/inc/vcl/bitmapex.hxx11
-rw-r--r--vcl/source/gdi/bitmapex.cxx78
-rw-r--r--vcl/source/gdi/gdimtf.cxx35
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 <vcl/bmpacc.hxx>
+#include <vcl/bitmapex.hxx>
+
#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<sal_Int64>( (BitmapEx*) NULL ) );
+ aRV = uno::Any( reinterpret_cast<sal_Int64>( (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<sal_Int64>( 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<X11Surface*>(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<QuartzSurface*>(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 <vcl/alpha.hxx>
#include <tools/color.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+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 <ctype.h>
#include <rtl/crc.h>
@@ -39,6 +38,13 @@
#include <image.h>
#include <impimagetree.hxx>
+// BitmapEx::Create
+#include <salbmp.hxx>
+#include <salinst.hxx>
+#include <svdata.hxx>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+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<const sal_Int64*>(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<sal_Int64>( 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<const sal_Int64*>(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;
}
}
}