diff options
author | Caolán McNamara <caolanm@redhat.com> | 2015-11-25 13:40:28 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2015-11-25 15:45:57 +0000 |
commit | c1774eb6a34d68b8a083ce1e919d634b700583c4 (patch) | |
tree | ac2541a3848ae85c9e97f6712ae28c3ce24de509 /vcl | |
parent | 872c1b7654510daa4a6974150490623745d931bf (diff) |
gtk3: implement drawAlphaBitmap for svp/gtk3 backend
mostly anyway
Change-Id: I21d7f46ba018c3ed81093873da35b883efa44d66
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/headless/svpgdi.cxx | 252 | ||||
-rw-r--r-- | vcl/inc/headless/svpgdi.hxx | 2 |
2 files changed, 194 insertions, 60 deletions
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 98e5b6f7090b..84b4b3228f69 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -64,6 +64,62 @@ rDevice #endif } +namespace +{ +#if CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR < 10 + struct cairo_rectangle_int_t + { + double x; + double y; + double width; + double height; + }; +#endif + + cairo_rectangle_int_t getFillDamage(cairo_t* cr) + { + cairo_rectangle_int_t extents; + double x1, y1, x2, y2; + + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; +#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 10) + cairo_region_t *region = cairo_region_create_rectangle(&extents); + + cairo_fill_extents(cr, &x1, &y1, &x2, &y2); + extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; + cairo_region_intersect_rectangle(region, &extents); + + cairo_region_get_extents(region, &extents); + cairo_region_destroy(region); +#endif + + return extents; + } + + cairo_rectangle_int_t getStrokeDamage(cairo_t* cr) + { + cairo_rectangle_int_t extents; + double x1, y1, x2, y2; + + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; +#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 10) + cairo_region_t *region = cairo_region_create_rectangle(&extents); + + cairo_stroke_extents(cr, &x1, &y1, &x2, &y2); + extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; + cairo_region_intersect_rectangle(region, &extents); + + cairo_region_get_extents(region, &extents); + cairo_region_destroy(region); +#endif + + return extents; + } + +} + #ifndef IOS bool SvpSalGraphics::blendBitmap( const SalTwoRect&, const SalBitmap& /*rBitmap*/ ) @@ -78,11 +134,134 @@ bool SvpSalGraphics::blendAlphaBitmap( const SalTwoRect&, const SalBitmap&, cons return false; } -bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ ) +bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap ) { - // TODO(P3) implement alpha blending - SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); - return false; + bool bRet = false; + (void)rTR; (void)rSourceBitmap; (void)rAlphaBitmap; +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0) + if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap alpha depth case: " << rAlphaBitmap.GetBitCount()); + return false; + } + + if (rTR.mnSrcWidth != rTR.mnDestWidth || rTR.mnSrcHeight != rTR.mnDestHeight) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap scale case"); + return false; + } + + cairo_surface_t* source = nullptr; + + const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSourceBitmap); + const basebmp::BitmapDeviceSharedPtr& rSrcBmp = rSrc.getBitmap(); + + SvpSalBitmap aTmpBmp; + if (rSourceBitmap.GetBitCount() != 32) + { + //big stupid copy here + static bool bWarnedOnce; + SAL_WARN_IF(!bWarnedOnce, "vcl.gdi", "non default depth bitmap, slow convert, upscale the input"); + bWarnedOnce = true; + Size aSize = rSourceBitmap.GetSize(); + aTmpBmp.Create(aSize, 0, BitmapPalette()); + assert(aTmpBmp.GetBitCount() == 32); + basegfx::B2IBox aRect(0, 0, aSize.Width(), aSize.Height()); + const basebmp::BitmapDeviceSharedPtr& rTmpSrc = aTmpBmp.getBitmap(); + rTmpSrc->drawBitmap(rSrcBmp, aRect, aRect, basebmp::DrawMode::Paint ); + source = createCairoSurface(rTmpSrc); + } + else + source = createCairoSurface(rSrcBmp); + + if (!source) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); + return false; + } + + const SvpSalBitmap& rMask = static_cast<const SvpSalBitmap&>(rAlphaBitmap); + const basebmp::BitmapDeviceSharedPtr& rMaskBmp = rMask.getBitmap(); + + cairo_surface_t *mask = nullptr; + + unsigned char* pAlphaBits = nullptr; + + basegfx::B2IVector size = rMaskBmp->getSize(); + sal_Int32 nStride = rMaskBmp->getScanlineStride(); + basebmp::RawMemorySharedArray data = rMaskBmp->getBuffer(); + + if (rAlphaBitmap.GetBitCount() == 8) + { + // the alpha values need to be inverted for Cairo + // so big stupid copy and invert here + const int nImageSize = size.getY() * nStride; + const unsigned char* pSrcBits = data.get(); + pAlphaBits = new unsigned char[nImageSize]; + memcpy(pAlphaBits, pSrcBits, nImageSize); + + // TODO: make upper layers use standard alpha + long* pLDst = reinterpret_cast<long*>(pAlphaBits); + for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst ) + *pLDst = ~*pLDst; + + char* pCDst = reinterpret_cast<char*>(pLDst); + for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst ) + *pCDst = ~*pCDst; + + mask = cairo_image_surface_create_for_data(pAlphaBits, + CAIRO_FORMAT_A8, + size.getX(), size.getY(), + nStride); + } + else + { + mask = cairo_image_surface_create_for_data(data.get(), + CAIRO_FORMAT_A1, + size.getX(), size.getY(), + nStride); + } + + if (!mask) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); + cairo_surface_destroy(source); + delete[] pAlphaBits; + return false; + } + + cairo_t* cr = getCairoContext(); + assert(cr && m_aDevice->isTopDown()); + + clipRegion(cr); + + cairo_rectangle_int_t extents; + basebmp::IBitmapDeviceDamageTrackerSharedPtr xDamageTracker(m_aDevice->getDamageTracker()); + + cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); + + cairo_set_source_surface(cr, source, rTR.mnDestX - rTR.mnSrcX, rTR.mnDestY - rTR.mnSrcY); + + if (xDamageTracker) + extents = getFillDamage(cr); + + cairo_clip(cr); + cairo_mask_surface(cr, mask, rTR.mnDestX - rTR.mnSrcX, rTR.mnDestY - rTR.mnSrcY); + + cairo_surface_flush(cairo_get_target(cr)); + cairo_surface_destroy(mask); + cairo_surface_destroy(source); + delete[] pAlphaBits; + cairo_destroy(cr); // unref + + if (xDamageTracker) + { + xDamageTracker->damaged(basegfx::B2IBox(extents.x, extents.y, extents.x + extents.width, + extents.y + extents.height)); + } + bRet = true; +#endif + return bRet; } bool SvpSalGraphics::drawTransformedBitmap( @@ -142,61 +321,6 @@ void SvpSalGraphics::clipRegion(cairo_t* cr) cairo_clip(cr); } } -namespace -{ -#if CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR < 10 - struct cairo_rectangle_int_t - { - double x; - double y; - double width; - double height; - }; -#endif - - cairo_rectangle_int_t getFillDamage(cairo_t* cr) - { - cairo_rectangle_int_t extents; - double x1, y1, x2, y2; - - cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; -#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 10) - cairo_region_t *region = cairo_region_create_rectangle(&extents); - - cairo_fill_extents(cr, &x1, &y1, &x2, &y2); - extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; - cairo_region_intersect_rectangle(region, &extents); - - cairo_region_get_extents(region, &extents); - cairo_region_destroy(region); -#endif - - return extents; - } - - cairo_rectangle_int_t getStrokeDamage(cairo_t* cr) - { - cairo_rectangle_int_t extents; - double x1, y1, x2, y2; - - cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; -#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 10) - cairo_region_t *region = cairo_region_create_rectangle(&extents); - - cairo_stroke_extents(cr, &x1, &y1, &x2, &y2); - extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1; - cairo_region_intersect_rectangle(region, &extents); - - cairo_region_get_extents(region, &extents); - cairo_region_destroy(region); -#endif - - return extents; - } - -} bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency) { @@ -1086,7 +1210,7 @@ bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uLong ) return false; } -cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr &rBuffer) +cairo_surface_t* SvpSalGraphics::createCairoSurface(const basebmp::BitmapDeviceSharedPtr &rBuffer) { if (!isCairoCompatible(rBuffer)) return nullptr; @@ -1105,6 +1229,14 @@ cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr nFormat, size.getX(), size.getY(), nStride); + return target; +} + +cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr &rBuffer) +{ + cairo_surface_t *target = createCairoSurface(rBuffer); + if (!target) + return nullptr; cairo_t* cr = cairo_create(target); cairo_surface_destroy(target); return cr; diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index 944ac83e3ff7..1adbc72b2819 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -47,6 +47,7 @@ class GlyphCache; class ServerFont; typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; class VCL_DLLPUBLIC SvpSalGraphics : public SalGraphics { @@ -214,6 +215,7 @@ public: #endif // ENABLE_CAIRO_CANVAS cairo_t* getCairoContext() const; + static cairo_surface_t* createCairoSurface(const basebmp::BitmapDeviceSharedPtr& rBuffer); static cairo_t* createCairoContext(const basebmp::BitmapDeviceSharedPtr& rBuffer); void clipRegion(cairo_t* cr); }; |