Bug 1028288 Add canvas global transparency support to svgs. r=roc

This commit is contained in:
James Kolb 2014-08-02 16:14:53 +09:00
parent aa56c9c4fb
commit 4cce70609b
9 changed files with 56 additions and 33 deletions

View File

@ -9,6 +9,8 @@
#include "nsIServiceManager.h"
#include "nsMathUtils.h"
#include "SVGPreserveAspectRatio.h"
#include "SVGImageContext.h"
#include "nsContentUtils.h"
@ -3432,7 +3434,7 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
} else {
DrawDirectlyToCanvas(drawInfo, &bounds, dx, dy, dw, dh,
sx, sy, sw, sh, imgSize);
sx, sy, sw, sh, imgSize, CurrentState().globalAlpha);
}
RedrawUser(gfxRect(dx, dy, dw, dh));
@ -3443,7 +3445,8 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
const nsLayoutUtils::DirectDrawInfo& image,
mgfx::Rect* bounds, double dx, double dy,
double dw, double dh, double sx, double sy,
double sw, double sh, gfxIntSize imgSize)
double sw, double sh, gfxIntSize imgSize,
gfxFloat opacity)
{
gfxMatrix contextMatrix;
@ -3469,12 +3472,14 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
// FLAG_CLAMP is added for increased performance
uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP;
SVGImageContext svgContext(SVGPreserveAspectRatio(), opacity);
nsresult rv = image.mImgContainer->
Draw(context, GraphicsFilter::FILTER_GOOD, transformMatrix,
gfxRect(gfxPoint(dx, dy), gfxIntSize(dw, dh)),
nsIntRect(nsIntPoint(0, 0), gfxIntSize(imgSize.width, imgSize.height)),
gfxIntSize(imgSize.width, imgSize.height), nullptr, image.mWhichFrame,
modifiedFlags);
gfxIntSize(imgSize.width, imgSize.height),
&svgContext, image.mWhichFrame, modifiedFlags);
NS_ENSURE_SUCCESS_VOID(rv);
}

View File

@ -667,7 +667,8 @@ protected:
void DrawDirectlyToCanvas(const nsLayoutUtils::DirectDrawInfo& image,
mozilla::gfx::Rect* bounds, double dx, double dy,
double dw, double dh, double sx, double sy,
double sw, double sh, gfxIntSize imgSize);
double sw, double sh, gfxIntSize imgSize,
gfxFloat opacity);
nsString& GetFont()
{

View File

@ -31,7 +31,8 @@ gfxSurfaceDrawable::Draw(gfxContext* aContext,
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform)
const gfxMatrix& aTransform,
gfxFloat aOpacity)
{
ExtendMode extend = ExtendMode::CLAMP;
@ -50,7 +51,7 @@ 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 +61,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 +97,16 @@ gfxCallbackDrawable::Draw(gfxContext* aContext,
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform)
const gfxMatrix& aTransform,
gfxFloat aOpacity)
{
if (aRepeat && !mSurfaceDrawable) {
if ((aRepeat || aOpacity != 1.0) && !mSurfaceDrawable) {
mSurfaceDrawable = MakeSurfaceDrawable(aFilter);
}
if (mSurfaceDrawable)
return mSurfaceDrawable->Draw(aContext, aFillRect, aRepeat, aFilter,
aTransform);
aTransform, aOpacity);
if (mCallback)
return (*mCallback)(aContext, aFillRect, aFilter, aTransform);
@ -159,7 +161,8 @@ gfxPatternDrawable::Draw(gfxContext* aContext,
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform)
const gfxMatrix& aTransform,
gfxFloat aOpacity)
{
if (!mPattern)
return false;
@ -174,7 +177,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext,
// will happen through this Draw() method with aRepeat = false.
nsRefPtr<gfxCallbackDrawable> callbackDrawable = MakeCallbackDrawable();
return callbackDrawable->Draw(aContext, aFillRect, true, aFilter,
aTransform);
aTransform, aOpacity);
}
aContext->NewPath();
@ -182,7 +185,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;
}

View File

@ -38,7 +38,8 @@ public:
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform = gfxMatrix()) = 0;
const gfxMatrix& aTransform = gfxMatrix(),
gfxFloat aOpacity = 1.0) = 0;
virtual gfxIntSize Size() { return mSize; }
protected:
@ -62,7 +63,8 @@ public:
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform = gfxMatrix());
const gfxMatrix& aTransform = gfxMatrix(),
gfxFloat aOpacity = 1.0);
protected:
mozilla::RefPtr<mozilla::gfx::SourceSurface> mSourceSurface;
@ -107,7 +109,8 @@ public:
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform = gfxMatrix());
const gfxMatrix& aTransform = gfxMatrix(),
gfxFloat aOpacity = 1.0);
protected:
already_AddRefed<gfxSurfaceDrawable> MakeSurfaceDrawable(const GraphicsFilter aFilter = GraphicsFilter::FILTER_FAST);
@ -130,7 +133,8 @@ public:
const gfxRect& aFillRect,
bool aRepeat,
const GraphicsFilter& aFilter,
const gfxMatrix& aTransform = gfxMatrix());
const gfxMatrix& aTransform = gfxMatrix(),
gfxFloat aOpacity = 1.0);
protected:
already_AddRefed<gfxCallbackDrawable> MakeCallbackDrawable();

View File

@ -575,7 +575,8 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
const gfxRect& aFill,
const SurfaceFormat aFormat,
GraphicsFilter aFilter,
uint32_t aImageFlags)
uint32_t aImageFlags,
gfxFloat aOpacity)
{
PROFILER_LABEL("gfxUtils", "DrawPixelSnapped",
js::ProfileEntry::Category::GRAPHICS);
@ -625,7 +626,7 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
}
#endif
drawable->Draw(aContext, aFill, doTile, aFilter, userSpaceToImageSpace);
drawable->Draw(aContext, aFill, doTile, aFilter, userSpaceToImageSpace, aOpacity);
}
/* static */ int

View File

@ -80,7 +80,8 @@ public:
const gfxRect& aFill,
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.

View File

@ -880,18 +880,20 @@ VectorImage::Draw(gfxContext* aContext,
aSVGContext, animTime, aFlags));
}
gfxFloat opacity = aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0;
// Draw.
if (drawable) {
Show(drawable, params);
Show(drawable, params, opacity);
} else {
CreateDrawableAndShow(params);
CreateDrawableAndShow(params, opacity);
}
return NS_OK;
}
void
VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams)
VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams, gfxFloat aOpacity)
{
mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize);
mSVGDocumentWrapper->FlushImageTransformInvalidation();
@ -912,7 +914,7 @@ VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams)
// The image is too big to fit in the cache:
!SurfaceCache::CanHold(aParams.imageRect.Size());
if (bypassCache)
return Show(svgDrawable, aParams);
return Show(svgDrawable, aParams, aOpacity);
// Try to create an offscreen surface.
RefPtr<gfx::DrawTarget> target =
@ -922,7 +924,7 @@ VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams)
// up way too big. Generally it also wouldn't fit in the cache, but the prefs
// could be set such that the cache isn't the limiting factor.
if (!target)
return Show(svgDrawable, aParams);
return Show(svgDrawable, aParams, aOpacity);
nsRefPtr<gfxContext> ctx = new gfxContext(target);
@ -949,12 +951,12 @@ VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams)
// to draw before returning from this function.
nsRefPtr<gfxDrawable> drawable =
new gfxSurfaceDrawable(surface, ThebesIntSize(aParams.imageRect.Size()));
Show(drawable, aParams);
Show(drawable, aParams, aOpacity);
}
void
VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams, gfxFloat aOpacity)
{
MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now");
gfxUtils::DrawPixelSnapped(aParams.context, aDrawable,
@ -962,7 +964,7 @@ VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
aParams.subimage, aParams.sourceRect,
ThebesIntRect(aParams.imageRect), aParams.fill,
SurfaceFormat::B8G8R8A8,
aParams.filter, aParams.flags);
aParams.filter, aParams.flags, aOpacity);
MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
mRenderingObserver->ResumeHonoringInvalidations();

View File

@ -86,8 +86,8 @@ protected:
virtual nsresult StopAnimation();
virtual bool ShouldAnimate();
void CreateDrawableAndShow(const SVGDrawingParameters& aParams);
void Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams);
void CreateDrawableAndShow(const SVGDrawingParameters& aParams, gfxFloat aOpacity);
void Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams, gfxFloat aOpacity);
private:
void CancelAllListeners();

View File

@ -18,14 +18,19 @@ class SVGImageContext
public:
SVGImageContext() { }
SVGImageContext(SVGPreserveAspectRatio aPreserveAspectRatio)
: mPreserveAspectRatio(aPreserveAspectRatio)
SVGImageContext(SVGPreserveAspectRatio aPreserveAspectRatio,
gfxFloat aOpacity = 1.0)
: mPreserveAspectRatio(aPreserveAspectRatio), mGlobalOpacity(aOpacity)
{ }
const SVGPreserveAspectRatio& GetPreserveAspectRatio() const {
return mPreserveAspectRatio;
}
gfxFloat GetGlobalOpacity() const {
return mGlobalOpacity;
}
bool operator==(const SVGImageContext& aOther) const {
return mPreserveAspectRatio == aOther.mPreserveAspectRatio;
}
@ -40,6 +45,7 @@ public:
private:
SVGPreserveAspectRatio mPreserveAspectRatio;
gfxFloat mGlobalOpacity;
};
} // namespace mozilla