refactor: move ImageData to web extension (#22295)

Signed-off-by: Leo Kettmeir <crowlkats@toaxl.com>
This commit is contained in:
Leo Kettmeir 2024-02-07 01:11:15 +01:00 committed by GitHub
parent 89ae2d88b8
commit 1007358768
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 258 additions and 239 deletions

View File

@ -13,30 +13,18 @@ const {
SymbolFor,
TypeError,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeGetSymbolToStringTag,
Uint8Array,
Uint8ClampedArray,
MathCeil,
PromiseResolve,
PromiseReject,
RangeError,
} = primordials;
webidl.converters["PredefinedColorSpace"] = webidl.createEnumConverter(
"PredefinedColorSpace",
[
"srgb",
"display-p3",
],
);
webidl.converters["ImageDataSettings"] = webidl.createDictionaryConverter(
"ImageDataSettings",
[
{ key: "colorSpace", converter: webidl.converters["PredefinedColorSpace"] },
],
);
import {
_data,
_height,
_width,
ImageDataPrototype,
} from "ext:deno_web/16_image_data.js";
webidl.converters["ImageOrientation"] = webidl.createEnumConverter(
"ImageOrientation",
@ -115,194 +103,6 @@ webidl.converters["ImageBitmapOptions"] = webidl.createDictionaryConverter(
],
);
const _data = Symbol("[[data]]");
const _width = Symbol("[[width]]");
const _height = Symbol("[[height]]");
class ImageData {
/** @type {number} */
[_width];
/** @type {height} */
[_height];
/** @type {Uint8Array} */
[_data];
/** @type {'srgb' | 'display-p3'} */
#colorSpace;
constructor(arg0, arg1, arg2 = undefined, arg3 = undefined) {
webidl.requiredArguments(
arguments.length,
2,
'Failed to construct "ImageData"',
);
this[webidl.brand] = webidl.brand;
let sourceWidth;
let sourceHeight;
let data;
let settings;
const prefix = "Failed to construct 'ImageData'";
// Overload: new ImageData(data, sw [, sh [, settings ] ])
if (
arguments.length > 3 ||
TypedArrayPrototypeGetSymbolToStringTag(arg0) === "Uint8ClampedArray"
) {
data = webidl.converters.Uint8ClampedArray(arg0, prefix, "Argument 1");
sourceWidth = webidl.converters["unsigned long"](
arg1,
prefix,
"Argument 2",
);
const dataLength = TypedArrayPrototypeGetLength(data);
if (webidl.type(arg2) !== "Undefined") {
sourceHeight = webidl.converters["unsigned long"](
arg2,
prefix,
"Argument 3",
);
}
settings = webidl.converters["ImageDataSettings"](
arg3,
prefix,
"Argument 4",
);
if (dataLength === 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data has zero elements.",
"InvalidStateError",
);
}
if (dataLength % 4 !== 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not a multiple of 4.",
"InvalidStateError",
);
}
if (sourceWidth < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source width is zero or not a number.",
"IndexSizeError",
);
}
if (webidl.type(sourceHeight) !== "Undefined" && sourceHeight < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source height is zero or not a number.",
"IndexSizeError",
);
}
if (dataLength / 4 % sourceWidth !== 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).",
"IndexSizeError",
);
}
if (
webidl.type(sourceHeight) !== "Undefined" &&
(sourceWidth * sourceHeight * 4 !== dataLength)
) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not equal to (4 * width * height).",
"IndexSizeError",
);
}
if (webidl.type(sourceHeight) === "Undefined") {
this[_height] = dataLength / 4 / sourceWidth;
} else {
this[_height] = sourceHeight;
}
this.#colorSpace = settings.colorSpace ?? "srgb";
this[_width] = sourceWidth;
this[_data] = data;
return;
}
// Overload: new ImageData(sw, sh [, settings])
sourceWidth = webidl.converters["unsigned long"](
arg0,
prefix,
"Argument 1",
);
sourceHeight = webidl.converters["unsigned long"](
arg1,
prefix,
"Argument 2",
);
settings = webidl.converters["ImageDataSettings"](
arg2,
prefix,
"Argument 3",
);
if (sourceWidth < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source width is zero or not a number.",
"IndexSizeError",
);
}
if (sourceHeight < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source height is zero or not a number.",
"IndexSizeError",
);
}
this.#colorSpace = settings.colorSpace ?? "srgb";
this[_width] = sourceWidth;
this[_height] = sourceHeight;
this[_data] = new Uint8ClampedArray(sourceWidth * sourceHeight * 4);
}
get width() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_width];
}
get height() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_height];
}
get data() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_data];
}
get colorSpace() {
webidl.assertBranded(this, ImageDataPrototype);
return this.#colorSpace;
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(ImageDataPrototype, this),
keys: [
"data",
"width",
"height",
"colorSpace",
],
}),
inspectOptions,
);
}
}
const ImageDataPrototype = ImageData.prototype;
const _bitmapData = Symbol("[[bitmapData]]");
const _detached = Symbol("[[detached]]");
class ImageBitmap {
@ -549,4 +349,4 @@ function getBitmapData(imageBitmap) {
internals.getBitmapData = getBitmapData;
export { _bitmapData, _detached, createImageBitmap, ImageBitmap, ImageData };
export { _bitmapData, _detached, createImageBitmap, ImageBitmap };

View File

@ -5,34 +5,6 @@
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/** @category Web APIs */
declare type PredefinedColorSpace = "srgb" | "display-p3";
/** @category Web APIs */
declare interface ImageDataSettings {
readonly colorSpace?: PredefinedColorSpace;
}
/** @category Web APIs */
declare interface ImageData {
readonly colorSpace: PredefinedColorSpace;
readonly data: Uint8ClampedArray;
readonly height: number;
readonly width: number;
}
/** @category Web APIs */
declare var ImageData: {
prototype: ImageData;
new (sw: number, sh: number, settings?: ImageDataSettings): ImageData;
new (
data: Uint8ClampedArray,
sw: number,
sh?: number,
settings?: ImageDataSettings,
): ImageData;
};
/** @category Web APIs */
declare type ColorSpaceConversion = "default" | "none";

219
ext/web/16_image_data.js Normal file
View File

@ -0,0 +1,219 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { primordials } from "ext:core/mod.js";
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
const {
ObjectPrototypeIsPrototypeOf,
Symbol,
SymbolFor,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeGetSymbolToStringTag,
Uint8ClampedArray,
} = primordials;
webidl.converters["PredefinedColorSpace"] = webidl.createEnumConverter(
"PredefinedColorSpace",
[
"srgb",
"display-p3",
],
);
webidl.converters["ImageDataSettings"] = webidl.createDictionaryConverter(
"ImageDataSettings",
[
{ key: "colorSpace", converter: webidl.converters["PredefinedColorSpace"] },
],
);
const _data = Symbol("[[data]]");
const _width = Symbol("[[width]]");
const _height = Symbol("[[height]]");
class ImageData {
/** @type {number} */
[_width];
/** @type {height} */
[_height];
/** @type {Uint8Array} */
[_data];
/** @type {'srgb' | 'display-p3'} */
#colorSpace;
constructor(arg0, arg1, arg2 = undefined, arg3 = undefined) {
webidl.requiredArguments(
arguments.length,
2,
'Failed to construct "ImageData"',
);
this[webidl.brand] = webidl.brand;
let sourceWidth;
let sourceHeight;
let data;
let settings;
const prefix = "Failed to construct 'ImageData'";
// Overload: new ImageData(data, sw [, sh [, settings ] ])
if (
arguments.length > 3 ||
TypedArrayPrototypeGetSymbolToStringTag(arg0) === "Uint8ClampedArray"
) {
data = webidl.converters.Uint8ClampedArray(arg0, prefix, "Argument 1");
sourceWidth = webidl.converters["unsigned long"](
arg1,
prefix,
"Argument 2",
);
const dataLength = TypedArrayPrototypeGetLength(data);
if (webidl.type(arg2) !== "Undefined") {
sourceHeight = webidl.converters["unsigned long"](
arg2,
prefix,
"Argument 3",
);
}
settings = webidl.converters["ImageDataSettings"](
arg3,
prefix,
"Argument 4",
);
if (dataLength === 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data has zero elements.",
"InvalidStateError",
);
}
if (dataLength % 4 !== 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not a multiple of 4.",
"InvalidStateError",
);
}
if (sourceWidth < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source width is zero or not a number.",
"IndexSizeError",
);
}
if (webidl.type(sourceHeight) !== "Undefined" && sourceHeight < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source height is zero or not a number.",
"IndexSizeError",
);
}
if (dataLength / 4 % sourceWidth !== 0) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).",
"IndexSizeError",
);
}
if (
webidl.type(sourceHeight) !== "Undefined" &&
(sourceWidth * sourceHeight * 4 !== dataLength)
) {
throw new DOMException(
"Failed to construct 'ImageData': The input data length is not equal to (4 * width * height).",
"IndexSizeError",
);
}
if (webidl.type(sourceHeight) === "Undefined") {
this[_height] = dataLength / 4 / sourceWidth;
} else {
this[_height] = sourceHeight;
}
this.#colorSpace = settings.colorSpace ?? "srgb";
this[_width] = sourceWidth;
this[_data] = data;
return;
}
// Overload: new ImageData(sw, sh [, settings])
sourceWidth = webidl.converters["unsigned long"](
arg0,
prefix,
"Argument 1",
);
sourceHeight = webidl.converters["unsigned long"](
arg1,
prefix,
"Argument 2",
);
settings = webidl.converters["ImageDataSettings"](
arg2,
prefix,
"Argument 3",
);
if (sourceWidth < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source width is zero or not a number.",
"IndexSizeError",
);
}
if (sourceHeight < 1) {
throw new DOMException(
"Failed to construct 'ImageData': The source height is zero or not a number.",
"IndexSizeError",
);
}
this.#colorSpace = settings.colorSpace ?? "srgb";
this[_width] = sourceWidth;
this[_height] = sourceHeight;
this[_data] = new Uint8ClampedArray(sourceWidth * sourceHeight * 4);
}
get width() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_width];
}
get height() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_height];
}
get data() {
webidl.assertBranded(this, ImageDataPrototype);
return this[_data];
}
get colorSpace() {
webidl.assertBranded(this, ImageDataPrototype);
return this.#colorSpace;
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(ImageDataPrototype, this),
keys: [
"data",
"width",
"height",
"colorSpace",
],
}),
inspectOptions,
);
}
}
const ImageDataPrototype = ImageData.prototype;
export { _data, _height, _width, ImageData, ImageDataPrototype };

View File

@ -1237,3 +1237,31 @@ declare var DecompressionStream: {
declare function reportError(
error: any,
): void;
/** @category Web APIs */
declare type PredefinedColorSpace = "srgb" | "display-p3";
/** @category Web APIs */
declare interface ImageDataSettings {
readonly colorSpace?: PredefinedColorSpace;
}
/** @category Web APIs */
declare interface ImageData {
readonly colorSpace: PredefinedColorSpace;
readonly data: Uint8ClampedArray;
readonly height: number;
readonly width: number;
}
/** @category Web APIs */
declare var ImageData: {
prototype: ImageData;
new (sw: number, sh: number, settings?: ImageDataSettings): ImageData;
new (
data: Uint8ClampedArray,
sw: number,
sh?: number,
settings?: ImageDataSettings,
): ImageData;
};

View File

@ -117,6 +117,7 @@ deno_core::extension!(deno_web,
"13_message_port.js",
"14_compression.js",
"15_performance.js",
"16_image_data.js",
],
options = {
blob_store: Arc<BlobStore>,

View File

@ -30,6 +30,7 @@ import * as messagePort from "ext:deno_web/13_message_port.js";
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import * as imageData from "ext:deno_web/16_image_data.js";
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
import { unstableIds } from "ext:runtime/90_deno_ns.js";
@ -60,10 +61,7 @@ const windowOrWorkerGlobalScope = {
FileReader: core.propNonEnumerable(fileReader.FileReader),
FormData: core.propNonEnumerable(formData.FormData),
Headers: core.propNonEnumerable(headers.Headers),
ImageData: core.propNonEnumerableLazyLoaded(
(image) => image.ImageData,
loadImage,
),
ImageData: core.propNonEnumerable(imageData.ImageData),
ImageBitmap: core.propNonEnumerableLazyLoaded(
(image) => image.ImageBitmap,
loadImage,

View File

@ -223,6 +223,7 @@
"ext:deno_web/13_message_port.js": "../ext/web/13_message_port.js",
"ext:deno_web/14_compression.js": "../ext/web/14_compression.js",
"ext:deno_web/15_performance.js": "../ext/web/15_performance.js",
"ext:deno_web/16_image_data.js": "../ext/web/16_image_data.js",
"ext:deno_webidl/00_webidl.js": "../ext/webidl/00_webidl.js",
"ext:deno_websocket/01_websocket.js": "../ext/websocket/01_websocket.js",
"ext:deno_websocket/02_websocketstream.js": "../ext/websocket/02_websocketstream.js",