Bug 1682612 - Check for ArrayBuffer Detach/Transfer in texImage2D(ImageData). r=gfx-reviewers,aosmond

Differential Revision: https://phabricator.services.mozilla.com/D141689
This commit is contained in:
Kelsey Gilbert 2022-03-21 23:21:42 +00:00
parent 30bc9c7098
commit e780e343c7
5 changed files with 80 additions and 48 deletions

View File

@ -3955,10 +3955,6 @@ Maybe<webgl::TexUnpackBlobDesc> FromImageBitmap(
GLenum target, Maybe<uvec3> size, const dom::ImageBitmap& imageBitmap,
ErrorResult* const out_rv);
webgl::TexUnpackBlobDesc FromImageData(GLenum target, Maybe<uvec3> size,
const dom::ImageData& imageData,
dom::Uint8ClampedArray* const scopedArr);
Maybe<webgl::TexUnpackBlobDesc> FromOffscreenCanvas(
const ClientWebGLContext&, GLenum target, Maybe<uvec3> 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<uint8_t*>(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<size_t>(imageSize.width) * imageSize.height * 4;
MOZ_RELEASE_ASSERT(sizeFromDims.isValid() &&
sizeFromDims.value() == dataSize);
const RefPtr<gfx::DataSourceSurface> 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) {

View File

@ -32,7 +32,15 @@ template <typename T>
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<JSObject*> 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<ImageData> 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<JSObject*> mData;
~ImageData() { DropData(); }
};
} // namespace dom

View File

@ -72,41 +72,6 @@ Maybe<TexUnpackBlobDesc> FromImageBitmap(const GLenum target, Maybe<uvec3> size,
false});
}
TexUnpackBlobDesc FromImageData(const GLenum target, Maybe<uvec3> 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<uint8_t*>(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<gfx::DataSourceSurface> 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) {

View File

@ -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]

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<script src='/tests/SimpleTest/SimpleTest.js'></script>
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
</head>
<body>
<script>
'use strict';
const ab = new ArrayBuffer(4);
const ta = new Uint8ClampedArray(ab);
const idata = new ImageData(ta, 1);
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const worker = new Worker('worker.js');
worker.postMessage([ab], [ab]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 1, gl.RGB, idata.width, idata.height, 0, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, idata);
const err = gl.getError();
window.ok = window.ok || console.log;
ok(err == gl.INVALID_VALUE, 'texImage2D(ImageData) with Transferred ArrayBuffer is INVALID_VALUE');
</script>
</body>
</html>