From e780e343c7d98835a63ebf260aff0b0ffec0e3f1 Mon Sep 17 00:00:00 2001 From: Kelsey Gilbert Date: Mon, 21 Mar 2022 23:21:42 +0000 Subject: [PATCH] Bug 1682612 - Check for ArrayBuffer Detach/Transfer in texImage2D(ImageData). r=gfx-reviewers,aosmond Differential Revision: https://phabricator.services.mozilla.com/D141689 --- dom/canvas/ClientWebGLContext.cpp | 51 ++++++++++++++++--- dom/canvas/ImageData.h | 17 ++++--- dom/canvas/WebGLTextureUpload.cpp | 35 ------------- dom/canvas/test/webgl-mochitest/mochitest.ini | 1 + ...test_imagedata_transfered_arraybuffer.html | 24 +++++++++ 5 files changed, 80 insertions(+), 48 deletions(-) create mode 100644 dom/canvas/test/webgl-mochitest/test_imagedata_transfered_arraybuffer.html diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index 194c1eb1199c..6edbffc6cddb 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -3955,10 +3955,6 @@ Maybe FromImageBitmap( GLenum target, Maybe size, const dom::ImageBitmap& imageBitmap, ErrorResult* const out_rv); -webgl::TexUnpackBlobDesc FromImageData(GLenum target, Maybe size, - const dom::ImageData& imageData, - dom::Uint8ClampedArray* const scopedArr); - Maybe FromOffscreenCanvas( const ClientWebGLContext&, GLenum target, Maybe size, const dom::OffscreenCanvas& src, ErrorResult* const out_error); @@ -4075,8 +4071,51 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget, } if (src.mImageData) { - return Some(webgl::FromImageData(imageTarget, size, *(src.mImageData), - &scopedArr)); + const auto& imageData = *src.mImageData; + MOZ_RELEASE_ASSERT(scopedArr.Init(imageData.GetDataObject())); + scopedArr.ComputeState(); + const auto dataSize = scopedArr.Length(); + const auto data = reinterpret_cast(scopedArr.Data()); + if (!data) { + // Neutered, e.g. via Transfer + EnqueueError(LOCAL_GL_INVALID_VALUE, + "ImageData.data.buffer is Detached. (Maybe you Transfered " + "it to a Worker?"); + return {}; + } + + // - + + const gfx::IntSize imageSize(imageData.Width(), imageData.Height()); + const auto sizeFromDims = + CheckedInt(imageSize.width) * imageSize.height * 4; + MOZ_RELEASE_ASSERT(sizeFromDims.isValid() && + sizeFromDims.value() == dataSize); + + const RefPtr surf = + gfx::Factory::CreateWrappingDataSourceSurface( + data, imageSize.width * 4, imageSize, + gfx::SurfaceFormat::R8G8B8A8); + MOZ_ASSERT(surf); + + // - + + const auto imageUSize = *uvec2::FromSize(imageSize); + const auto concreteSize = + size.valueOr(uvec3{imageUSize.x, imageUSize.y, 1}); + + // WhatWG "HTML Living Standard" (30 October 2015): + // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned + // as non-premultiplied alpha values." + return Some(webgl::TexUnpackBlobDesc{imageTarget, + concreteSize, + gfxAlphaType::NonPremult, + {}, + {}, + Some(imageUSize), + nullptr, + {}, + surf}); } if (src.mOffscreenCanvas) { diff --git a/dom/canvas/ImageData.h b/dom/canvas/ImageData.h index 80b4f09a3bf1..71a1e803758b 100644 --- a/dom/canvas/ImageData.h +++ b/dom/canvas/ImageData.h @@ -32,7 +32,15 @@ template class Optional; class ImageData final : public nsISupports { - ~ImageData() { DropData(); } + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageData) + + const uint32_t mWidth; + const uint32_t mHeight; + + private: + JS::Heap mData; public: ImageData(uint32_t aWidth, uint32_t aHeight, JSObject& aData) @@ -40,9 +48,6 @@ class ImageData final : public nsISupports { HoldData(); } - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageData) - static already_AddRefed Constructor(const GlobalObject& aGlobal, const uint32_t aWidth, const uint32_t aHeight, @@ -75,9 +80,7 @@ class ImageData final : public nsISupports { void DropData(); ImageData() = delete; - - uint32_t mWidth, mHeight; - JS::Heap mData; + ~ImageData() { DropData(); } }; } // namespace dom diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 74ee216a6629..2135cb813e2d 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -72,41 +72,6 @@ Maybe FromImageBitmap(const GLenum target, Maybe size, false}); } -TexUnpackBlobDesc FromImageData(const GLenum target, Maybe size, - const dom::ImageData& imageData, - dom::Uint8ClampedArray* const scopedArr) { - MOZ_RELEASE_ASSERT(scopedArr->Init(imageData.GetDataObject())); - scopedArr->ComputeState(); - const size_t dataSize = scopedArr->Length(); - const auto data = reinterpret_cast(scopedArr->Data()); - - const gfx::IntSize imageISize(imageData.Width(), imageData.Height()); - const auto imageUSize = *uvec2::FromSize(imageISize); - const size_t stride = imageUSize.x * 4; - const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8; - MOZ_ALWAYS_TRUE(dataSize == stride * imageUSize.y); - - const RefPtr surf = - gfx::Factory::CreateWrappingDataSourceSurface(data, stride, imageISize, - surfFormat); - MOZ_ASSERT(surf); - - //// - - if (!size) { - size.emplace(imageUSize.x, imageUSize.y, 1); - } - - //// - - // WhatWG "HTML Living Standard" (30 October 2015): - // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as - // non-premultiplied alpha values." - return {target, size.value(), gfxAlphaType::NonPremult, - {}, {}, Some(imageUSize), - nullptr, {}, surf}; -} - static layers::SurfaceDescriptor Flatten(const layers::SurfaceDescriptor& sd) { const auto sdType = sd.type(); if (sdType != layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) { diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini index f75e68c0760b..d7f71a3d26a9 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.ini +++ b/dom/canvas/test/webgl-mochitest/mochitest.ini @@ -74,6 +74,7 @@ support-files = ../captureStream_common.js fail-if = (os == 'android') || (os == 'linux') || (os == 'mac') [test_hidden_alpha.html] [test_hidden_depth_stencil.html] +[test_imagedata_transfered_arraybuffer.html] [test_implicit_color_buffer_float.html] [test_highp_fs.html] [test_no_arr_points.html] diff --git a/dom/canvas/test/webgl-mochitest/test_imagedata_transfered_arraybuffer.html b/dom/canvas/test/webgl-mochitest/test_imagedata_transfered_arraybuffer.html new file mode 100644 index 000000000000..18eed39a4361 --- /dev/null +++ b/dom/canvas/test/webgl-mochitest/test_imagedata_transfered_arraybuffer.html @@ -0,0 +1,24 @@ + + + + + + + + + + +