From 74a487913a2161e43e8b1145632f94f8611d0b65 Mon Sep 17 00:00:00 2001 From: James Kolb Date: Fri, 29 Aug 2014 23:04:34 +0900 Subject: [PATCH] Bug 1028288 Add canvas global transparency support to svgs. r=seth --- dom/canvas/CanvasRenderingContext2D.cpp | 5 ++++- gfx/thebes/gfxDrawable.cpp | 18 +++++++++++------- gfx/thebes/gfxDrawable.h | 4 ++++ gfx/thebes/gfxUtils.cpp | 7 ++++--- gfx/thebes/gfxUtils.h | 3 ++- image/src/VectorImage.cpp | 4 +++- layout/svg/SVGImageContext.h | 19 +++++++++++++++---- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index fbc3ce465a7d..2e2e5c34d3ce 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -9,6 +9,7 @@ #include "nsIServiceManager.h" #include "nsMathUtils.h" +#include "SVGImageContext.h" #include "nsContentUtils.h" @@ -3484,11 +3485,13 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas( // FLAG_CLAMP is added for increased performance, since we never tile here. uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP; + SVGImageContext svgContext(scaledImageSize, Nothing(), CurrentState().globalAlpha); + nsresult rv = image.mImgContainer-> Draw(context, scaledImageSize, ImageRegion::Create(gfxRect(src.x, src.y, src.width, src.height)), image.mWhichFrame, GraphicsFilter::FILTER_GOOD, - Nothing(), modifiedFlags); + Some(svgContext), modifiedFlags); NS_ENSURE_SUCCESS_VOID(rv); } diff --git a/gfx/thebes/gfxDrawable.cpp b/gfx/thebes/gfxDrawable.cpp index 7a641ccfd384..a5328810d4fb 100644 --- a/gfx/thebes/gfxDrawable.cpp +++ b/gfx/thebes/gfxDrawable.cpp @@ -31,6 +31,7 @@ gfxSurfaceDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity, const gfxMatrix& aTransform) { ExtendMode extend = ExtendMode::CLAMP; @@ -50,7 +51,8 @@ gfxSurfaceDrawable::Draw(gfxContext* aContext, if (aContext->CurrentOperator() == gfxContext::OPERATOR_CLEAR) { dt->ClearRect(fillRect); - } else if (aContext->CurrentOperator() == gfxContext::OPERATOR_SOURCE) { + } else if (aContext->CurrentOperator() == gfxContext::OPERATOR_SOURCE && + aOpacity == 1.0) { // Emulate cairo operator source which is bound by mask! dt->ClearRect(fillRect); dt->FillRect(fillRect, pattern); @@ -60,7 +62,7 @@ gfxSurfaceDrawable::Draw(gfxContext* aContext, aContext->CurrentAntialiasMode() == gfxContext::MODE_ALIASED ? AntialiasMode::NONE : AntialiasMode::SUBPIXEL; - dt->FillRect(fillRect, pattern, DrawOptions(1.0f, op, aaMode)); + dt->FillRect(fillRect, pattern, DrawOptions(aOpacity, op, aaMode)); } return true; } @@ -96,15 +98,16 @@ gfxCallbackDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity, const gfxMatrix& aTransform) { - if (aRepeat && !mSurfaceDrawable) { + if ((aRepeat || aOpacity != 1.0) && !mSurfaceDrawable) { mSurfaceDrawable = MakeSurfaceDrawable(aFilter); } if (mSurfaceDrawable) return mSurfaceDrawable->Draw(aContext, aFillRect, aRepeat, aFilter, - aTransform); + aOpacity, aTransform); if (mCallback) return (*mCallback)(aContext, aFillRect, aFilter, aTransform); @@ -137,7 +140,7 @@ public: const GraphicsFilter& aFilter, const gfxMatrix& aTransform = gfxMatrix()) { - return mDrawable->Draw(aContext, aFillRect, false, aFilter, + return mDrawable->Draw(aContext, aFillRect, false, aFilter, 1.0, aTransform); } private: @@ -159,6 +162,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity, const gfxMatrix& aTransform) { if (!mPattern) @@ -174,7 +178,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext, // will happen through this Draw() method with aRepeat = false. nsRefPtr callbackDrawable = MakeCallbackDrawable(); return callbackDrawable->Draw(aContext, aFillRect, true, aFilter, - aTransform); + aOpacity, aTransform); } aContext->NewPath(); @@ -182,7 +186,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext, mPattern->SetMatrix(aTransform * oldMatrix); aContext->SetPattern(mPattern); aContext->Rectangle(aFillRect); - aContext->Fill(); + aContext->FillWithOpacity(aOpacity); mPattern->SetMatrix(oldMatrix); return true; } diff --git a/gfx/thebes/gfxDrawable.h b/gfx/thebes/gfxDrawable.h index 4aeb3d5d4112..e566f1a6a264 100644 --- a/gfx/thebes/gfxDrawable.h +++ b/gfx/thebes/gfxDrawable.h @@ -38,6 +38,7 @@ public: const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity = 1.0, const gfxMatrix& aTransform = gfxMatrix()) = 0; virtual gfxIntSize Size() { return mSize; } @@ -62,6 +63,7 @@ public: const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity = 1.0, const gfxMatrix& aTransform = gfxMatrix()); protected: @@ -107,6 +109,7 @@ public: const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity = 1.0, const gfxMatrix& aTransform = gfxMatrix()); protected: @@ -130,6 +133,7 @@ public: const gfxRect& aFillRect, bool aRepeat, const GraphicsFilter& aFilter, + gfxFloat aOpacity = 1.0, const gfxMatrix& aTransform = gfxMatrix()); protected: diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 86b436a1fc86..44f07bb530d9 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -407,7 +407,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable, nsRefPtr tmpCtx = new gfxContext(target); tmpCtx->SetOperator(OptimalFillOperator()); aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true, - GraphicsFilter::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft())); + GraphicsFilter::FILTER_FAST, 1.0, gfxMatrix().Translate(needed.TopLeft())); RefPtr surface = target->Snapshot(); nsRefPtr drawable = new gfxSurfaceDrawable(surface, size, gfxMatrix().Translate(-needed.TopLeft())); @@ -567,7 +567,8 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext, const ImageRegion& aRegion, const SurfaceFormat aFormat, GraphicsFilter aFilter, - uint32_t aImageFlags) + uint32_t aImageFlags, + gfxFloat aOpacity) { PROFILER_LABEL("gfxUtils", "DrawPixelSnapped", js::ProfileEntry::Category::GRAPHICS); @@ -617,7 +618,7 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext, } #endif - drawable->Draw(aContext, aRegion.Rect(), doTile, aFilter); + drawable->Draw(aContext, aRegion.Rect(), doTile, aFilter, aOpacity); } /* static */ int diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index fc9cf759226a..476ad40273e7 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -81,7 +81,8 @@ public: const ImageRegion& aRegion, const mozilla::gfx::SurfaceFormat aFormat, GraphicsFilter aFilter, - uint32_t aImageFlags = imgIContainer::FLAG_NONE); + uint32_t aImageFlags = imgIContainer::FLAG_NONE, + gfxFloat aOpacity = 1.0); /** * Clip aContext to the region aRegion. diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp index 7820e2c54168..45cf49f310dd 100644 --- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -779,6 +779,7 @@ struct SVGDrawingParameters , viewportSize(aSVGContext ? aSVGContext->GetViewportSize() : aSize) , animationTime(aAnimationTime) , flags(aFlags) + , opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0) { } gfxContext* context; @@ -790,6 +791,7 @@ struct SVGDrawingParameters nsIntSize viewportSize; float animationTime; uint32_t flags; + gfxFloat opacity; }; //****************************************************************************** @@ -929,7 +931,7 @@ VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams) ThebesIntSize(aParams.size), aParams.region, SurfaceFormat::B8G8R8A8, - aParams.filter, aParams.flags); + aParams.filter, aParams.flags, aParams.opacity); MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now"); mRenderingObserver->ResumeHonoringInvalidations(); diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h index a78c764c0ae8..c6265e0bc2d2 100644 --- a/layout/svg/SVGImageContext.h +++ b/layout/svg/SVGImageContext.h @@ -19,12 +19,16 @@ namespace mozilla { class SVGImageContext { public: - SVGImageContext() { } + SVGImageContext() + : mGlobalOpacity(1.0) + { } SVGImageContext(nsIntSize aViewportSize, - Maybe aPreserveAspectRatio) + Maybe aPreserveAspectRatio, + gfxFloat aOpacity = 1.0) : mViewportSize(aViewportSize) , mPreserveAspectRatio(aPreserveAspectRatio) + , mGlobalOpacity(aOpacity) { } const nsIntSize& GetViewportSize() const { @@ -35,9 +39,14 @@ public: return mPreserveAspectRatio; } + gfxFloat GetGlobalOpacity() const { + return mGlobalOpacity; + } + bool operator==(const SVGImageContext& aOther) const { return mViewportSize == aOther.mViewportSize && - mPreserveAspectRatio == aOther.mPreserveAspectRatio; + mPreserveAspectRatio == aOther.mPreserveAspectRatio && + mGlobalOpacity == aOther.mGlobalOpacity; } bool operator!=(const SVGImageContext& aOther) const { @@ -47,7 +56,8 @@ public: uint32_t Hash() const { return HashGeneric(mViewportSize.width, mViewportSize.height, - mPreserveAspectRatio.map(HashPAR).valueOr(0)); + mPreserveAspectRatio.map(HashPAR).valueOr(0), + HashBytes(&mGlobalOpacity, sizeof(gfxFloat))); } private: @@ -57,6 +67,7 @@ private: nsIntSize mViewportSize; Maybe mPreserveAspectRatio; + gfxFloat mGlobalOpacity; }; } // namespace mozilla