author | Matt Woodrow <mwoodrow@mozilla.com> |
Thu, 17 Apr 2014 17:31:44 +1200 | |
changeset 178971 | c609ffeef5244970aae38f43599f2f35d55f7aad |
parent 178970 | 2d7b34276247f26a53faca28dada0543900e7a04 |
child 178972 | abc11addc2d10017095a8f2911d763a6f0998577 |
push id | 42410 |
push user | mwoodrow@mozilla.com |
push date | Thu, 17 Apr 2014 10:13:46 +0000 |
treeherder | mozilla-inbound@5e815640f63d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
bugs | 997014 |
milestone | 31.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h +++ b/content/canvas/public/nsICanvasRenderingContextInternal.h @@ -9,18 +9,18 @@ #include "nsISupports.h" #include "nsIInputStream.h" #include "nsIDocShell.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "GraphicsFilter.h" #include "mozilla/RefPtr.h" #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \ -{ 0xf74397d9, 0x25d9, 0x43ed, \ - { 0xb4, 0x6a, 0xf5, 0x4e, 0xa1, 0x17, 0xae, 0x6e } } +{ 0x06166dd1, 0xd540, 0x4f29, \ + { 0x91, 0x5c, 0x08, 0x7d, 0xce, 0x1f, 0x79, 0x59 } } class gfxContext; class gfxASurface; class nsDisplayListBuilder; namespace mozilla { namespace layers { class CanvasLayer; @@ -36,20 +36,16 @@ class SourceSurface; class nsICanvasRenderingContextInternal : public nsISupports { public: typedef mozilla::layers::CanvasLayer CanvasLayer; typedef mozilla::layers::LayerManager LayerManager; NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID) - enum { - RenderFlagPremultAlpha = 0x1 - }; - void SetCanvasElement(mozilla::dom::HTMLCanvasElement* aParentCanvas) { mCanvasElement = aParentCanvas; } mozilla::dom::HTMLCanvasElement* GetParentObject() const { return mCanvasElement; } @@ -61,21 +57,16 @@ public: #endif // Sets the dimensions of the canvas, in pixels. Called // whenever the size of the element changes. NS_IMETHOD SetDimensions(int32_t width, int32_t height) = 0; NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) = 0; - // Render the canvas at the origin of the given gfxContext - NS_IMETHOD Render(gfxContext *ctx, - GraphicsFilter aFilter, - uint32_t aFlags = RenderFlagPremultAlpha) = 0; - // Creates an image buffer. Returns null on failure. virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0; // Gives you a stream containing the image represented by this context. // The format is given in aMimeTime, for example "image/png". // // If the image format does not support transparency or aIncludeTransparency // is false, alpha will be discarded and the result will be the image
--- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -1049,61 +1049,16 @@ CanvasRenderingContext2D::SetIsIPC(bool mIPC = isIPC; ClearTarget(); } return NS_OK; } NS_IMETHODIMP -CanvasRenderingContext2D::Render(gfxContext *ctx, GraphicsFilter aFilter, uint32_t aFlags) -{ - nsresult rv = NS_OK; - - EnsureTarget(); - if (!IsTargetValid()) { - return NS_ERROR_FAILURE; - } - - nsRefPtr<gfxASurface> surface; - - if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) { - return NS_ERROR_FAILURE; - } - - nsRefPtr<gfxPattern> pat = new gfxPattern(surface); - - pat->SetFilter(aFilter); - pat->SetExtend(gfxPattern::EXTEND_PAD); - - gfxContext::GraphicsOperator op = ctx->CurrentOperator(); - if (mOpaque) - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - - // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee - // pixel alignment for this stuff! - ctx->NewPath(); - ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat); - ctx->Fill(); - - if (mOpaque) - ctx->SetOperator(op); - - if (!(aFlags & RenderFlagPremultAlpha)) { - nsRefPtr<gfxASurface> curSurface = ctx->CurrentSurface(); - nsRefPtr<gfxImageSurface> gis = curSurface->GetAsImageSurface(); - MOZ_ASSERT(gis, "If non-premult alpha, must be able to get image surface!"); - - gfxUtils::UnpremultiplyImageSurface(gis); - } - - return rv; -} - -NS_IMETHODIMP CanvasRenderingContext2D::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions) { if (aOptions.isNullOrUndefined()) { return NS_OK; } ContextAttributes2D attributes; NS_ENSURE_TRUE(attributes.Init(aCx, aOptions), NS_ERROR_UNEXPECTED);
--- a/content/canvas/src/CanvasRenderingContext2D.h +++ b/content/canvas/src/CanvasRenderingContext2D.h @@ -452,19 +452,16 @@ public: #ifdef DEBUG virtual int32_t GetWidth() const MOZ_OVERRIDE; virtual int32_t GetHeight() const MOZ_OVERRIDE; #endif // nsICanvasRenderingContextInternal NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE; NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE; - NS_IMETHOD Render(gfxContext *ctx, - GraphicsFilter aFilter, - uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE; NS_IMETHOD GetInputStream(const char* aMimeType, const char16_t* aEncoderOptions, nsIInputStream **aStream) MOZ_OVERRIDE; NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE; mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) MOZ_OVERRIDE { EnsureTarget();
--- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -620,58 +620,16 @@ WebGLContext::SetDimensions(int32_t widt MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil); MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias); MOZ_ASSERT(gl->Caps().preserve == caps.preserve); reporter.SetSuccessful(); return NS_OK; } -NS_IMETHODIMP -WebGLContext::Render(gfxContext *ctx, GraphicsFilter f, uint32_t aFlags) -{ - if (!gl) - return NS_OK; - - nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight), - gfxImageFormat::ARGB32); - if (surf->CairoStatus() != 0) - return NS_ERROR_FAILURE; - - gl->MakeCurrent(); - ReadScreenIntoImageSurface(gl, surf); - - bool srcPremultAlpha = mOptions.premultipliedAlpha; - bool dstPremultAlpha = aFlags & RenderFlagPremultAlpha; - - if (!srcPremultAlpha && dstPremultAlpha) { - gfxUtils::PremultiplyImageSurface(surf); - } else if (srcPremultAlpha && !dstPremultAlpha) { - gfxUtils::UnpremultiplyImageSurface(surf); - } - surf->MarkDirty(); - - nsRefPtr<gfxPattern> pat = new gfxPattern(surf); - pat->SetFilter(f); - - // Pixels from ReadPixels will be "upside down" compared to - // what cairo wants, so draw with a y-flip and a translte to - // flip them. - gfxMatrix m; - m.Translate(gfxPoint(0.0, mHeight)); - m.Scale(1.0, -1.0); - pat->SetMatrix(m); - - ctx->NewPath(); - ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat); - ctx->Fill(); - - return NS_OK; -} - void WebGLContext::LoseOldestWebGLContextIfLimitExceeded() { #ifdef MOZ_GFX_OPTIMIZE_MOBILE // some mobile devices can't have more than 8 GL contexts overall const size_t kMaxWebGLContextsPerPrincipal = 2; const size_t kMaxWebGLContexts = 4; #else const size_t kMaxWebGLContextsPerPrincipal = 16; @@ -753,54 +711,53 @@ void WebGLContext::LoseOldestWebGLContex } void WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) { *aImageBuffer = nullptr; *aFormat = 0; - nsRefPtr<gfxImageSurface> imgsurf = - new gfxImageSurface(gfxIntSize(mWidth, mHeight), - gfxImageFormat::ARGB32); + // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied + bool premult; + RefPtr<SourceSurface> snapshot = + GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult); + if (!snapshot) { + return; + } + MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!"); - if (!imgsurf || imgsurf->CairoStatus()) { + RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface(); + + DataSourceSurface::MappedSurface map; + if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) { return; } - nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf); - if (!ctx || ctx->HasError()) { + static const fallible_t fallible = fallible_t(); + uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; + if (!imageBuffer) { + dataSurface->Unmap(); return; } + memcpy(imageBuffer, map.mData, mWidth * mHeight * 4); - // Use Render() to make sure that appropriate y-flip gets applied - uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0; - nsresult rv = Render(ctx, GraphicsFilter::FILTER_NEAREST, flags); - if (NS_FAILED(rv)) { - return; - } + dataSurface->Unmap(); int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; if (!mOptions.premultipliedAlpha) { // We need to convert to INPUT_FORMAT_RGBA, otherwise // we are automatically considered premult, and unpremult'd. // Yes, it is THAT silly. // Except for different lossy conversions by color, // we could probably just change the label, and not change the data. - gfxUtils::ConvertBGRAtoRGBA(imgsurf); + gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4); format = imgIEncoder::INPUT_FORMAT_RGBA; } - static const fallible_t fallible = fallible_t(); - uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; - if (!imageBuffer) { - return; - } - memcpy(imageBuffer, imgsurf->Data(), mWidth * mHeight * 4); - *aImageBuffer = imageBuffer; *aFormat = format; } NS_IMETHODIMP WebGLContext::GetInputStream(const char* aMimeType, const char16_t* aEncoderOptions, nsIInputStream **aStream) @@ -1377,17 +1334,18 @@ WebGLContext::MakeContextCurrent() const mozilla::TemporaryRef<mozilla::gfx::SourceSurface> WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha) { if (!gl) return nullptr; nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight), - gfxImageFormat::ARGB32); + gfxImageFormat::ARGB32, + mWidth * 4, 0, false); if (surf->CairoStatus() != 0) { return nullptr; } gl->MakeCurrent(); ReadScreenIntoImageSurface(gl, surf); if (aPremultAlpha) {
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -160,19 +160,16 @@ public: virtual int32_t GetWidth() const MOZ_OVERRIDE; virtual int32_t GetHeight() const MOZ_OVERRIDE; #endif NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE; NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD Reset() MOZ_OVERRIDE { /* (InitializeWithSurface) */ return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD Render(gfxContext *ctx, - GraphicsFilter f, - uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE; virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat); NS_IMETHOD GetInputStream(const char* aMimeType, const char16_t* aEncoderOptions, nsIInputStream **aStream) MOZ_OVERRIDE; NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE; mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha) MOZ_OVERRIDE; NS_IMETHOD SetIsOpaque(bool b) MOZ_OVERRIDE { return NS_OK; };
--- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -241,16 +241,34 @@ gfxUtils::ConvertBGRAtoRGBA(gfxImageSurf dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = src[3]; } } } +void +gfxUtils::ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength) +{ + uint8_t *src = aData; + uint8_t *srcEnd = src + aLength; + + uint8_t buffer[4]; + for (; src != srcEnd; src += 4) { + buffer[0] = src[2]; + buffer[1] = src[1]; + buffer[2] = src[0]; + + src[0] = buffer[0]; + src[1] = buffer[1]; + src[2] = buffer[2]; + } +} + static bool IsSafeImageTransformComponent(gfxFloat aValue) { return aValue >= -32768 && aValue <= 32767; } #ifndef MOZ_GFX_OPTIMIZE_MOBILE /**
--- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -43,16 +43,17 @@ public: static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface, gfxImageSurface *aDestSurface = nullptr); static void UnpremultiplyImageSurface(gfxImageSurface *aSurface, gfxImageSurface *aDestSurface = nullptr); static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface); static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface, gfxImageSurface *aDestSurface = nullptr); + static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength); /** * Draw something drawable while working around limitations like bad support * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with * extreme user-space-to-image-space transforms. * * The input parameters here usually come from the output of our image * snapping algorithm in nsLayoutUtils.cpp.