зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1172796 - Part 7: Implements ImageBitmapRenderingContext. r=roc r=smaug
--HG-- extra : commitid : J5ynF4BHVHV
This commit is contained in:
Родитель
4144a07339
Коммит
3e61e4b4cf
|
@ -5579,9 +5579,9 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager)
|
|||
return mBufferProvider;
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
already_AddRefed<Layer>
|
||||
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<CanvasLayer> ret = aOldLayer;
|
||||
if (userData &&
|
||||
userData->IsForContext(this) &&
|
||||
static_cast<CanvasLayer*>(aOldLayer)->IsDataValid(data)) {
|
||||
RefPtr<Layer> ret = aOldLayer;
|
||||
return ret.forget();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -459,9 +459,9 @@ public:
|
|||
bool GetIsOpaque() override { return mOpaque; }
|
||||
NS_IMETHOD Reset() override;
|
||||
mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager);
|
||||
already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
CanvasLayer *aOldLayer,
|
||||
LayerManager *aManager) override;
|
||||
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
Layer *aOldLayer,
|
||||
LayerManager *aManager) override;
|
||||
virtual bool ShouldForceInactiveLayer(LayerManager *aManager) override;
|
||||
void MarkContextClean() override;
|
||||
void MarkContextCleanForFrameCapture() override;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ enum class CanvasContextType : uint8_t {
|
|||
NoContext,
|
||||
Canvas2D,
|
||||
WebGL1,
|
||||
WebGL2
|
||||
WebGL2,
|
||||
ImageBitmap
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -505,6 +505,14 @@ ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget)
|
|||
return surface.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<layers::Image>
|
||||
ImageBitmap::TransferAsImage()
|
||||
{
|
||||
RefPtr<layers::Image> image = mData;
|
||||
Close();
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
ImageBitmapCloneData*
|
||||
ImageBitmap::ToCloneData()
|
||||
{
|
||||
|
|
|
@ -100,6 +100,13 @@ public:
|
|||
already_AddRefed<gfx::SourceSurface>
|
||||
PrepareForDrawTarget(gfx::DrawTarget* aTarget);
|
||||
|
||||
/*
|
||||
* Transfer ownership of buffer to caller. So this function call
|
||||
* Close() implicitly.
|
||||
*/
|
||||
already_AddRefed<layers::Image>
|
||||
TransferAsImage();
|
||||
|
||||
ImageBitmapCloneData*
|
||||
ToCloneData();
|
||||
|
||||
|
|
|
@ -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<JSObject*> aGivenProto)
|
||||
{
|
||||
return ImageBitmapRenderingContextBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<layers::Image>
|
||||
ImageBitmapRenderingContext::ClipToIntrinsicSize()
|
||||
{
|
||||
if (!mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If image is larger than canvas intrinsic size, clip it to the intrinsic size.
|
||||
RefPtr<gfx::SourceSurface> surface;
|
||||
RefPtr<layers::Image> 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<DataSourceSurface>
|
||||
ImageBitmapRenderingContext::MatchWithIntrinsicSize()
|
||||
{
|
||||
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
|
||||
RefPtr<DataSourceSurface> 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<DrawTarget> 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<uint8_t[]>
|
||||
ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat)
|
||||
{
|
||||
*aFormat = 0;
|
||||
|
||||
if (!mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
|
||||
RefPtr<DataSourceSurface> 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<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
if (!encoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int32_t format = 0;
|
||||
UniquePtr<uint8_t[]> imageBuffer = GetImageBuffer(&format);
|
||||
if (!imageBuffer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(), format,
|
||||
encoder, aEncoderOptions, aStream);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::gfx::SourceSurface>
|
||||
ImageBitmapRenderingContext::GetSurfaceSnapshot(bool* aPremultAlpha)
|
||||
{
|
||||
if (!mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aPremultAlpha) {
|
||||
*aPremultAlpha = true;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> 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<Layer>
|
||||
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> imageLayer;
|
||||
|
||||
if (aOldLayer) {
|
||||
imageLayer = static_cast<ImageLayer*>(aOldLayer);
|
||||
} else {
|
||||
imageLayer = aManager->CreateImageLayer();
|
||||
}
|
||||
|
||||
RefPtr<ImageContainer> imageContainer = imageLayer->GetContainer();
|
||||
if (!imageContainer) {
|
||||
imageContainer = aManager->CreateImageContainer();
|
||||
imageLayer->SetContainer(imageContainer);
|
||||
}
|
||||
|
||||
nsAutoTArray<ImageContainer::NonOwningImage, 1> imageList;
|
||||
RefPtr<layers::Image> 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
|
||||
|
||||
}
|
||||
}
|
|
@ -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<JSObject*> 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<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
|
||||
NS_IMETHOD GetInputStream(const char* aMimeType,
|
||||
const char16_t* aEncoderOptions,
|
||||
nsIInputStream** aStream) override;
|
||||
|
||||
virtual already_AddRefed<mozilla::gfx::SourceSurface>
|
||||
GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override;
|
||||
|
||||
NS_IMETHOD SetIsOpaque(bool aIsOpaque) override;
|
||||
virtual bool GetIsOpaque() override;
|
||||
NS_IMETHOD Reset() override;
|
||||
virtual already_AddRefed<Layer> 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<gfx::DataSourceSurface> MatchWithIntrinsicSize();
|
||||
already_AddRefed<layers::Image> ClipToIntrinsicSize();
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
|
||||
RefPtr<layers::Image> mImage;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ImageBitmapRenderingContext_h */
|
|
@ -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<WebGLContext*>(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<WebGLContext*>(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<gl::SurfaceFactory> factory =
|
||||
gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
|
||||
UniquePtr<gl::SurfaceFactory> factory =
|
||||
gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
|
||||
|
||||
if (factory)
|
||||
screen->Morph(Move(factory));
|
||||
if (factory)
|
||||
screen->Morph(Move(factory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1131,9 +1131,9 @@ private:
|
|||
RefPtr<HTMLCanvasElement> mCanvas;
|
||||
};
|
||||
|
||||
already_AddRefed<layers::CanvasLayer>
|
||||
already_AddRefed<layers::Layer>
|
||||
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<layers::CanvasLayer> ret = oldLayer;
|
||||
RefPtr<layers::Layer> ret = oldLayer;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -331,8 +331,8 @@ public:
|
|||
return ActiveBoundTextureForTarget(texTarget);
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
GetCanvasLayer(nsDisplayListBuilder* builder, CanvasLayer* oldLayer,
|
||||
already_AddRefed<Layer>
|
||||
GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
|
||||
LayerManager* manager) override;
|
||||
|
||||
// Note that 'clean' here refers to its invalidation state, not the
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
|
|
@ -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<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* builder,
|
||||
CanvasLayer *oldLayer,
|
||||
LayerManager *manager) = 0;
|
||||
virtual already_AddRefed<Layer> 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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/js-worker">
|
||||
function ok(expect, msg) {
|
||||
postMessage({"type": "status", status: !!expect, msg: msg});
|
||||
}
|
||||
|
||||
onmessage = function(event) {
|
||||
var bitmap = event.data.bitmap;
|
||||
ok(!!bitmap, "Get the ImageBitmap from the main script.");
|
||||
|
||||
var offscreenCanvas = new OffscreenCanvas(64, 64);
|
||||
var ctx = offscreenCanvas.getContext('bitmaprenderer');
|
||||
ok(!!ctx, "Get bitmaprenderer context on worker.");
|
||||
|
||||
ctx.transferImageBitmap(bitmap);
|
||||
var resultBitmap = offscreenCanvas.transferToImageBitmap();
|
||||
postMessage({"type": "bitmap", bitmap: resultBitmap}, [resultBitmap]);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createCanvas(width, height) {
|
||||
var htmlCanvas = document.createElement('canvas');
|
||||
htmlCanvas.width = width;
|
||||
htmlCanvas.height = height;
|
||||
document.body.appendChild(htmlCanvas);
|
||||
return htmlCanvas;
|
||||
}
|
||||
|
||||
function runTest(canvasWidth, canvasHeight, nextTest) {
|
||||
var canvas1 = createCanvas(canvasWidth, canvasHeight);
|
||||
var ctx = canvas1.getContext("2d");
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
var canvasRef = createCanvas(90, 90);
|
||||
var ctx = canvasRef.getContext("2d");
|
||||
// Clear with black transparent first
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0)";
|
||||
ctx.fillRect(0, 0, 90, 90);
|
||||
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
createImageBitmap(canvas1).then(function(bmp) {
|
||||
document.body.removeChild(canvas1);
|
||||
|
||||
var canvas2 = createCanvas(90, 90);
|
||||
var ctx2 = canvas2.getContext("bitmaprenderer");
|
||||
ctx2.transferImageBitmap(bmp);
|
||||
|
||||
ok(canvasRef.toDataURL() == canvas2.toDataURL(), "toDataURL should return same result.");
|
||||
|
||||
// Exam render result
|
||||
canvasRef.style.display = "none";
|
||||
canvas2.style.display = "block";
|
||||
var snapshot = snapshotWindow(window);
|
||||
|
||||
canvasRef.style.display = "block";
|
||||
canvas2.style.display = "none";
|
||||
var snapshotRef = snapshotWindow(window);
|
||||
|
||||
var results = compareSnapshots(snapshot, snapshotRef, true);
|
||||
ok(results[0], "Screenshots should be the same");
|
||||
|
||||
document.body.removeChild(canvasRef);
|
||||
document.body.removeChild(canvas2);
|
||||
|
||||
nextTest();
|
||||
});
|
||||
}
|
||||
|
||||
function scaleTest() {
|
||||
var canvas1 = createCanvas(64, 64);
|
||||
var ctx = canvas1.getContext("2d");
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fillRect(0, 0, 64, 64);
|
||||
|
||||
var canvas2 = createCanvas(64, 64);
|
||||
var ctx2 = canvas2.getContext("2d");
|
||||
ctx2.fillStyle = "#00FF00";
|
||||
ctx2.fillRect(0, 0, 64, 64);
|
||||
|
||||
var p1 = createImageBitmap(canvas1);
|
||||
var p2 = createImageBitmap(canvas2);
|
||||
Promise.all([p1, p2]).then(function(bitmaps) {
|
||||
document.body.removeChild(canvas1);
|
||||
document.body.removeChild(canvas2);
|
||||
|
||||
// Create a large canvas then shrink.
|
||||
var canvas3 = createCanvas(128, 128);
|
||||
var ctx3 = canvas3.getContext("bitmaprenderer");
|
||||
ctx3.transferImageBitmap(bitmaps[0]);
|
||||
var snapshotLargeRef = snapshotWindow(window);
|
||||
|
||||
canvas3.width = 32;
|
||||
canvas3.height = 32;
|
||||
var snapshotSmall = snapshotWindow(window);
|
||||
document.body.removeChild(canvas3);
|
||||
|
||||
// Create a small canvas then grow.
|
||||
var canvas4 = createCanvas(32, 32);
|
||||
var ctx4 = canvas4.getContext("bitmaprenderer");
|
||||
ctx4.transferImageBitmap(bitmaps[1]);
|
||||
var snapshotSmallRef = snapshotWindow(window);
|
||||
|
||||
canvas4.width = 128;
|
||||
canvas4.height = 128;
|
||||
var snapshotLarge = snapshotWindow(window);
|
||||
document.body.removeChild(canvas4);
|
||||
|
||||
var resultsLarge = compareSnapshots(snapshotLarge, snapshotLargeRef, true);
|
||||
ok(resultsLarge[0], "Screenshots should be the same");
|
||||
|
||||
var resultsSmall = compareSnapshots(snapshotSmall, snapshotSmallRef, true);
|
||||
ok(resultsSmall[0], "Screenshots should be the same");
|
||||
runTestOnWorker();
|
||||
});
|
||||
}
|
||||
|
||||
function runTestOnWorker() {
|
||||
var canvas1 = createCanvas(64, 64);
|
||||
var ctx = canvas1.getContext("2d");
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fillRect(0, 0, 64, 64);
|
||||
|
||||
var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"});
|
||||
|
||||
var worker = new Worker(window.URL.createObjectURL(blob));
|
||||
|
||||
createImageBitmap(canvas1).then(function(bmp) {
|
||||
worker.postMessage({bitmap: bmp}, [bmp]);
|
||||
worker.onmessage = function(event) {
|
||||
if (event.data.type == "status") {
|
||||
ok(event.data.status, event.data.msg);
|
||||
} else if (event.data.type == "bitmap") {
|
||||
var canvas2 = createCanvas(64, 64);
|
||||
var ctx2 = canvas2.getContext('bitmaprenderer');
|
||||
ctx2.transferImageBitmap(event.data.bitmap);
|
||||
ok(canvas1.toDataURL() == canvas2.toDataURL(), 'toDataURL should be the same');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
]}, runTest.bind(this, 64, 64, runTest.bind(this, 128, 128, scaleTest)));
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1046,9 +1046,9 @@ HTMLCanvasElement::GetOpaqueAttr()
|
|||
return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
already_AddRefed<Layer>
|
||||
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<CanvasLayer> ret = aOldLayer;
|
||||
RefPtr<Layer> ret = aOldLayer;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
CanvasLayer *aOldLayer,
|
||||
LayerManager *aManager);
|
||||
already_AddRefed<Layer> 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.
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -265,6 +265,7 @@ WEBIDL_FILES = [
|
|||
'IDBTransaction.webidl',
|
||||
'IDBVersionChangeEvent.webidl',
|
||||
'ImageBitmap.webidl',
|
||||
'ImageBitmapRenderingContext.webidl',
|
||||
'ImageCapture.webidl',
|
||||
'ImageData.webidl',
|
||||
'ImageDocument.webidl',
|
||||
|
|
|
@ -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<CanvasLayer*>
|
||||
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
|
||||
RefPtr<CanvasLayer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager);
|
||||
RefPtr<Layer> 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> canvasLayer = static_cast<CanvasLayer*>(layer.get());
|
||||
canvasLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
|
||||
} else if (layer->GetType() == layers::Layer::TYPE_IMAGE) {
|
||||
RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get());
|
||||
imageLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
|
||||
}
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче