diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 5e89c391199..3896e9f7ca4 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -5579,9 +5579,9 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager) return mBufferProvider; } -already_AddRefed +already_AddRefed CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, + Layer *aOldLayer, LayerManager *aManager) { if (mOpaque || mIsSkiaGL) { @@ -5624,8 +5624,10 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, data.mBufferProvider = provider; } - if (userData && userData->IsForContext(this) && aOldLayer->IsDataValid(data)) { - RefPtr ret = aOldLayer; + if (userData && + userData->IsForContext(this) && + static_cast(aOldLayer)->IsDataValid(data)) { + RefPtr ret = aOldLayer; return ret.forget(); } } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index d2782b594d3..04c3bd89048 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -459,9 +459,9 @@ public: bool GetIsOpaque() override { return mOpaque; } NS_IMETHOD Reset() override; mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager); - already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, - LayerManager *aManager) override; + already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer *aOldLayer, + LayerManager *aManager) override; virtual bool ShouldForceInactiveLayer(LayerManager *aManager) override; void MarkContextClean() override; void MarkContextCleanForFrameCapture() override; diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp index 187260d97aa..07977c375ac 100644 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CanvasRenderingContextHelper.h" +#include "ImageBitmapRenderingContext.h" #include "ImageEncoder.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/Telemetry.h" @@ -151,6 +152,11 @@ CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType) return nullptr; break; + + case CanvasContextType::ImageBitmap: + ret = new ImageBitmapRenderingContext(); + + break; } MOZ_ASSERT(ret); diff --git a/dom/canvas/CanvasRenderingContextHelper.h b/dom/canvas/CanvasRenderingContextHelper.h index aab29b48369..b047d60fcfc 100644 --- a/dom/canvas/CanvasRenderingContextHelper.h +++ b/dom/canvas/CanvasRenderingContextHelper.h @@ -25,7 +25,8 @@ enum class CanvasContextType : uint8_t { NoContext, Canvas2D, WebGL1, - WebGL2 + WebGL2, + ImageBitmap }; /** diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp index 9d258c01f70..ac0e2684947 100644 --- a/dom/canvas/CanvasUtils.cpp +++ b/dom/canvas/CanvasUtils.cpp @@ -61,6 +61,11 @@ GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_typ } } + if (str.EqualsLiteral("bitmaprenderer")) { + *out_type = dom::CanvasContextType::ImageBitmap; + return true; + } + return false; } diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index 5652715c6fb..2c7c3d412a2 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -505,6 +505,14 @@ ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget) return surface.forget(); } +already_AddRefed +ImageBitmap::TransferAsImage() +{ + RefPtr image = mData; + Close(); + return image.forget(); +} + ImageBitmapCloneData* ImageBitmap::ToCloneData() { diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index baac5859ad9..4480efeef20 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -100,6 +100,13 @@ public: already_AddRefed PrepareForDrawTarget(gfx::DrawTarget* aTarget); + /* + * Transfer ownership of buffer to caller. So this function call + * Close() implicitly. + */ + already_AddRefed + TransferAsImage(); + ImageBitmapCloneData* ToCloneData(); diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp new file mode 100644 index 00000000000..b8b079eeb5c --- /dev/null +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -0,0 +1,303 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ImageBitmapRenderingContext.h" +#include "mozilla/dom/ImageBitmapRenderingContextBinding.h" +#include "ImageContainer.h" +#include "ImageLayers.h" + +namespace mozilla { +namespace dom { + +ImageBitmapRenderingContext::ImageBitmapRenderingContext() + : mWidth(0) + , mHeight(0) +{ +} + +ImageBitmapRenderingContext::~ImageBitmapRenderingContext() +{ + RemovePostRefreshObserver(); +} + +JSObject* +ImageBitmapRenderingContext::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return ImageBitmapRenderingContextBinding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed +ImageBitmapRenderingContext::ClipToIntrinsicSize() +{ + if (!mImage) { + return nullptr; + } + + // If image is larger than canvas intrinsic size, clip it to the intrinsic size. + RefPtr surface; + RefPtr result; + if (mWidth < mImage->GetSize().width || + mHeight < mImage->GetSize().height) { + surface = MatchWithIntrinsicSize(); + } else { + surface = mImage->GetAsSourceSurface(); + } + result = new layers::SourceSurfaceImage(gfx::IntSize(mWidth, mHeight), surface); + return result.forget(); +} + +void +ImageBitmapRenderingContext::TransferImageBitmap(ImageBitmap& aImageBitmap) +{ + Reset(); + mImage = aImageBitmap.TransferAsImage(); + + if (!mImage) { + return; + } + + Redraw(gfxRect(0, 0, mWidth, mHeight)); +} + +int32_t +ImageBitmapRenderingContext::GetWidth() const +{ + return mWidth; +} + +int32_t +ImageBitmapRenderingContext::GetHeight() const +{ + return mHeight; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight) +{ + mWidth = aWidth; + mHeight = aHeight; + return NS_OK; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::InitializeWithSurface(nsIDocShell* aDocShell, + gfxASurface* aSurface, + int32_t aWidth, + int32_t aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +already_AddRefed +ImageBitmapRenderingContext::MatchWithIntrinsicSize() +{ + RefPtr surface = mImage->GetAsSourceSurface(); + RefPtr temp = + Factory::CreateDataSourceSurface(IntSize(mWidth, mHeight), surface->GetFormat()); + if (!temp) { + return nullptr; + } + + DataSourceSurface::ScopedMap map(temp, DataSourceSurface::READ_WRITE); + if (!map.IsMapped()) { + return nullptr; + } + + RefPtr dt = + Factory::CreateDrawTargetForData(BackendType::CAIRO, + map.GetData(), + temp->GetSize(), + map.GetStride(), + temp->GetFormat()); + if (!dt) { + return nullptr; + } + + + dt->ClearRect(Rect(0, 0, mWidth, mHeight)); + dt->CopySurface(surface, + IntRect(0, 0, surface->GetSize().width, + surface->GetSize().height), + IntPoint(0, 0)); + + return temp.forget(); +} + +mozilla::UniquePtr +ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat) +{ + *aFormat = 0; + + if (!mImage) { + return nullptr; + } + + RefPtr surface = mImage->GetAsSourceSurface(); + RefPtr data = surface->GetDataSurface(); + if (!data) { + return nullptr; + } + + if (data->GetSize() != IntSize(mWidth, mHeight)) { + data = MatchWithIntrinsicSize(); + } + + *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB; + return SurfaceToPackedBGRA(data); +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::GetInputStream(const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** aStream) +{ + nsCString enccid("@mozilla.org/image/encoder;2?type="); + enccid += aMimeType; + nsCOMPtr encoder = do_CreateInstance(enccid.get()); + if (!encoder) { + return NS_ERROR_FAILURE; + } + + int32_t format = 0; + UniquePtr imageBuffer = GetImageBuffer(&format); + if (!imageBuffer) { + return NS_ERROR_FAILURE; + } + + return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(), format, + encoder, aEncoderOptions, aStream); +} + +already_AddRefed +ImageBitmapRenderingContext::GetSurfaceSnapshot(bool* aPremultAlpha) +{ + if (!mImage) { + return nullptr; + } + + if (aPremultAlpha) { + *aPremultAlpha = true; + } + + RefPtr surface = mImage->GetAsSourceSurface(); + if (surface->GetSize() != IntSize(mWidth, mHeight)) { + return MatchWithIntrinsicSize(); + } + + return surface.forget(); +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetIsOpaque(bool aIsOpaque) +{ + return NS_OK; +} + +bool +ImageBitmapRenderingContext::GetIsOpaque() +{ + return false; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::Reset() +{ + if (mCanvasElement) { + mCanvasElement->InvalidateCanvas(); + } + + mImage = nullptr; + + return NS_OK; +} + +already_AddRefed +ImageBitmapRenderingContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer* aOldLayer, + LayerManager* aManager) +{ + if (!mImage) { + // No DidTransactionCallback will be received, so mark the context clean + // now so future invalidations will be dispatched. + MarkContextClean(); + return nullptr; + } + + RefPtr imageLayer; + + if (aOldLayer) { + imageLayer = static_cast(aOldLayer); + } else { + imageLayer = aManager->CreateImageLayer(); + } + + RefPtr imageContainer = imageLayer->GetContainer(); + if (!imageContainer) { + imageContainer = aManager->CreateImageContainer(); + imageLayer->SetContainer(imageContainer); + } + + nsAutoTArray imageList; + RefPtr image = ClipToIntrinsicSize(); + imageList.AppendElement(ImageContainer::NonOwningImage(image)); + imageContainer->SetCurrentImages(imageList); + + return imageLayer.forget(); +} + +void +ImageBitmapRenderingContext::MarkContextClean() +{ +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::Redraw(const gfxRect& aDirty) +{ + if (!mCanvasElement) { + return NS_OK; + } + + mozilla::gfx::Rect rect = ToRect(aDirty); + mCanvasElement->InvalidateCanvasContent(&rect); + return NS_OK; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetIsIPC(bool aIsIPC) +{ + return NS_OK; +} + +void +ImageBitmapRenderingContext::DidRefresh() +{ +} + +void +ImageBitmapRenderingContext::MarkContextCleanForFrameCapture() +{ +} + +bool +ImageBitmapRenderingContext::IsContextCleanForFrameCapture() +{ + return true; +} + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext) + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmapRenderingContext, + mCanvasElement, + mOffscreenCanvas) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +} +} diff --git a/dom/canvas/ImageBitmapRenderingContext.h b/dom/canvas/ImageBitmapRenderingContext.h new file mode 100644 index 00000000000..aa5c5061119 --- /dev/null +++ b/dom/canvas/ImageBitmapRenderingContext.h @@ -0,0 +1,97 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ImageBitmapRenderingContext_h +#define ImageBitmapRenderingContext_h + +#include "nsICanvasRenderingContextInternal.h" +#include "nsWrapperCache.h" + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +class SourceSurface; +} + +namespace layers { +class Image; +class ImageContainer; +} + +namespace dom { + +/** + * The purpose of ImageBitmapRenderingContext is to provide a faster and efficient + * way to display ImageBitmap. Simply call TransferImageBitmap() then we'll transfer + * the surface of ImageBitmap to this context and then to use it to display. + * + * See more details in spec: https://wiki.whatwg.org/wiki/OffscreenCanvas + */ +class ImageBitmapRenderingContext final : + public nsICanvasRenderingContextInternal, + public nsWrapperCache +{ + virtual ~ImageBitmapRenderingContext(); + +public: + ImageBitmapRenderingContext(); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + // nsISupports interface + CC + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageBitmapRenderingContext) + + void TransferImageBitmap(ImageBitmap& aImageBitmap); + + // nsICanvasRenderingContextInternal + virtual int32_t GetWidth() const override; + virtual int32_t GetHeight() const override; + + NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override; + + NS_IMETHOD InitializeWithSurface(nsIDocShell* aDocShell, + gfxASurface* aSurface, + int32_t aWidth, + int32_t aHeight) override; + + virtual mozilla::UniquePtr GetImageBuffer(int32_t* aFormat) override; + NS_IMETHOD GetInputStream(const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** aStream) override; + + virtual already_AddRefed + GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override; + + NS_IMETHOD SetIsOpaque(bool aIsOpaque) override; + virtual bool GetIsOpaque() override; + NS_IMETHOD Reset() override; + virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer* aOldLayer, + LayerManager* aManager) override; + virtual void MarkContextClean() override; + + NS_IMETHOD Redraw(const gfxRect& aDirty) override; + NS_IMETHOD SetIsIPC(bool aIsIPC) override; + + virtual void DidRefresh() override; + + virtual void MarkContextCleanForFrameCapture() override; + virtual bool IsContextCleanForFrameCapture() override; + +protected: + already_AddRefed MatchWithIntrinsicSize(); + already_AddRefed ClipToIntrinsicSize(); + int32_t mWidth; + int32_t mHeight; + + RefPtr mImage; +}; + +} +} + +#endif /* ImageBitmapRenderingContext_h */ diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index e579799b77f..857da02aeac 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -121,7 +121,8 @@ OffscreenCanvas::GetContext(JSContext* aCx, } if (!(contextType == CanvasContextType::WebGL1 || - contextType == CanvasContextType::WebGL2)) + contextType == CanvasContextType::WebGL2 || + contextType == CanvasContextType::ImageBitmap)) { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); return nullptr; @@ -138,28 +139,31 @@ OffscreenCanvas::GetContext(JSContext* aCx, } if (mCanvasRenderer) { - WebGLContext* webGL = static_cast(mCurrentContext.get()); - gl::GLContext* gl = webGL->GL(); - mCanvasRenderer->mContext = mCurrentContext; - mCanvasRenderer->SetActiveThread(); - mCanvasRenderer->mGLContext = gl; - mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); + if (contextType == CanvasContextType::WebGL1 || + contextType == CanvasContextType::WebGL2) { + WebGLContext* webGL = static_cast(mCurrentContext.get()); + gl::GLContext* gl = webGL->GL(); + mCanvasRenderer->mContext = mCurrentContext; + mCanvasRenderer->SetActiveThread(); + mCanvasRenderer->mGLContext = gl; + mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); - if (ImageBridgeChild::IsCreated()) { - TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; - mCanvasClient = ImageBridgeChild::GetSingleton()-> - CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); - mCanvasRenderer->SetCanvasClient(mCanvasClient); + if (ImageBridgeChild::IsCreated()) { + TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; + mCanvasClient = ImageBridgeChild::GetSingleton()-> + CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); + mCanvasRenderer->SetCanvasClient(mCanvasClient); - gl::GLScreenBuffer* screen = gl->Screen(); - gl::SurfaceCaps caps = screen->mCaps; - auto forwarder = mCanvasClient->GetForwarder(); + gl::GLScreenBuffer* screen = gl->Screen(); + gl::SurfaceCaps caps = screen->mCaps; + auto forwarder = mCanvasClient->GetForwarder(); - UniquePtr factory = - gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); + UniquePtr factory = + gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); - if (factory) - screen->Morph(Move(factory)); + if (factory) + screen->Morph(Move(factory)); + } } } diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index b8bc7a14807..aa2fcad5ab3 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1131,9 +1131,9 @@ private: RefPtr mCanvas; }; -already_AddRefed +already_AddRefed WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, - CanvasLayer* oldLayer, + Layer* oldLayer, LayerManager* manager) { if (IsContextLost()) @@ -1141,7 +1141,7 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, if (!mResetLayer && oldLayer && oldLayer->HasUserData(&gWebGLLayerUserData)) { - RefPtr ret = oldLayer; + RefPtr ret = oldLayer; return ret.forget(); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 5e3d61722cd..74f475a3a2d 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -331,8 +331,8 @@ public: return ActiveBoundTextureForTarget(texTarget); } - already_AddRefed - GetCanvasLayer(nsDisplayListBuilder* builder, CanvasLayer* oldLayer, + already_AddRefed + GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer, LayerManager* manager) override; // Note that 'clean' here refers to its invalidation state, not the diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index da9182e06aa..7ea8448414b 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -34,6 +34,7 @@ EXPORTS.mozilla.dom += [ 'CanvasRenderingContextHelper.h', 'CanvasUtils.h', 'ImageBitmap.h', + 'ImageBitmapRenderingContext.h', 'ImageBitmapSource.h', 'ImageData.h', 'OffscreenCanvas.h', @@ -50,6 +51,7 @@ UNIFIED_SOURCES += [ 'DocumentRendererChild.cpp', 'DocumentRendererParent.cpp', 'ImageBitmap.cpp', + 'ImageBitmapRenderingContext.cpp', 'ImageData.cpp', 'OffscreenCanvas.cpp', ] diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index a18e4001bb1..2c446421fa5 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -26,6 +26,7 @@ class nsDisplayListBuilder; namespace mozilla { namespace layers { class CanvasLayer; +class Layer; class LayerManager; } // namespace layers namespace gfx { @@ -39,6 +40,7 @@ class nsICanvasRenderingContextInternal : { public: typedef mozilla::layers::CanvasLayer CanvasLayer; + typedef mozilla::layers::Layer Layer; typedef mozilla::layers::LayerManager LayerManager; NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID) @@ -129,9 +131,9 @@ public: // Return the CanvasLayer for this context, creating // one for the given layer manager if not available. - virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* builder, - CanvasLayer *oldLayer, - LayerManager *manager) = 0; + virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* builder, + Layer *oldLayer, + LayerManager *manager) = 0; // Return true if the canvas should be forced to be "inactive" to ensure // it can be drawn to the screen even if it's too large to be blitted by diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 5acdc488427..a79506f87e3 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -218,6 +218,7 @@ skip-if = toolkit != 'cocoa' [test_2d.path.rect.zero.6.html] disabled = bug 407107 [test_2d.strokeRect.zero.5.html] +[test_bitmaprenderer.html] [test_bug232227.html] [test_bug613794.html] [test_bug753758.html] diff --git a/dom/canvas/test/test_bitmaprenderer.html b/dom/canvas/test/test_bitmaprenderer.html new file mode 100644 index 00000000000..246b3d2c697 --- /dev/null +++ b/dom/canvas/test/test_bitmaprenderer.html @@ -0,0 +1,163 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + + diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 7d62acb5282..a07df8fa6a9 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -1046,9 +1046,9 @@ HTMLCanvasElement::GetOpaqueAttr() return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque); } -already_AddRefed +already_AddRefed HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, + Layer *aOldLayer, LayerManager *aManager) { // The address of sOffscreenCanvasLayerUserDataDummy is used as the user @@ -1064,7 +1064,7 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, if (mOffscreenCanvas) { if (!mResetLayer && aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { - RefPtr ret = aOldLayer; + RefPtr ret = aOldLayer; return ret.forget(); } diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 1d11a27706e..c7c30ef79af 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -31,6 +31,7 @@ namespace layers { class AsyncCanvasRenderer; class CanvasLayer; class Image; +class Layer; class LayerManager; } // namespace layers namespace gfx { @@ -120,6 +121,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement, typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer; typedef layers::CanvasLayer CanvasLayer; + typedef layers::Layer Layer; typedef layers::LayerManager LayerManager; public: @@ -308,9 +310,9 @@ public: * Helpers called by various users of Canvas */ - already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, - LayerManager *aManager); + already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer *aOldLayer, + LayerManager *aManager); // Should return true if the canvas layer should always be marked inactive. // We should return true here if we can't do accelerated compositing with // a non-BasicCanvasLayer. diff --git a/dom/webidl/ImageBitmapRenderingContext.webidl b/dom/webidl/ImageBitmapRenderingContext.webidl new file mode 100644 index 00000000000..4696427b2ea --- /dev/null +++ b/dom/webidl/ImageBitmapRenderingContext.webidl @@ -0,0 +1,36 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://wiki.whatwg.org/wiki/OffscreenCanvas + * + * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +// The new ImageBitmapRenderingContext is a canvas rendering context +// which only provides the functionality to replace the canvas's +// contents with the given ImageBitmap. Its context id (the first argument +// to getContext) is "bitmaprenderer". +[Exposed=(Window,Worker)] +interface ImageBitmapRenderingContext { + // Displays the given ImageBitmap in the canvas associated with this + // rendering context. Ownership of the ImageBitmap is transferred to + // the canvas. The caller may not use its reference to the ImageBitmap + // after making this call. (This semantic is crucial to enable prompt + // reclamation of expensive graphics resources, rather than relying on + // garbage collection to do so.) + // + // The ImageBitmap conceptually replaces the canvas's bitmap, but + // it does not change the canvas's intrinsic width or height. + // + // The ImageBitmap, when displayed, is clipped to the rectangle + // defined by the canvas's instrinsic width and height. Pixels that + // would be covered by the canvas's bitmap which are not covered by + // the supplied ImageBitmap are rendered transparent black. Any CSS + // styles affecting the display of the canvas are applied as usual. + void transferImageBitmap(ImageBitmap bitmap); +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index beae51d9c51..2234c287869 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -265,6 +265,7 @@ WEBIDL_FILES = [ 'IDBTransaction.webidl', 'IDBVersionChangeEvent.webidl', 'ImageBitmap.webidl', + 'ImageBitmapRenderingContext.webidl', 'ImageCapture.webidl', 'ImageData.webidl', 'ImageDocument.webidl', diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 5d16dc198e6..9254b1c0934 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -13,6 +13,7 @@ #include "nsDisplayList.h" #include "nsLayoutUtils.h" #include "nsStyleUtil.h" +#include "ImageLayers.h" #include "Layers.h" #include "ActiveLayerTracker.h" @@ -338,7 +339,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, CanvasLayer* oldLayer = static_cast (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); - RefPtr layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); + RefPtr layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); if (!layer) return nullptr; @@ -357,7 +358,13 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, transform.PreScale(destGFXRect.Width() / canvasSizeInPx.width, destGFXRect.Height() / canvasSizeInPx.height); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); - layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + if (layer->GetType() == layers::Layer::TYPE_CANVAS) { + RefPtr canvasLayer = static_cast(layer.get()); + canvasLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) { + RefPtr imageLayer = static_cast(layer.get()); + imageLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + } return layer.forget(); }