diff --git a/Cargo.lock b/Cargo.lock index 655b21708e4f06..36dc887fad29d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,6 +192,15 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" version = "1.3.2" @@ -1772,6 +1781,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "deno_geometry" +version = "0.1.0" +dependencies = [ + "deno_core", + "deno_error", + "nalgebra", + "thiserror 2.0.3", +] + [[package]] name = "deno_graph" version = "0.87.0" @@ -2330,6 +2349,7 @@ dependencies = [ "deno_fetch", "deno_ffi", "deno_fs", + "deno_geometry", "deno_http", "deno_io", "deno_kv", @@ -5018,6 +5038,16 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "md-5" version = "0.10.6" @@ -5175,6 +5205,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "nalgebra" +version = "0.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + [[package]] name = "napi-build" version = "1.2.1" @@ -5357,6 +5402,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -5383,6 +5437,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -6321,6 +6386,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cc3bcbdb1ddfc11e700e62968e6b4cc9c75bb466464ad28fb61c5b2c964418b" +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.10.0" @@ -6785,6 +6856,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + [[package]] name = "saffron" version = "0.1.0" @@ -7112,6 +7192,19 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "simd-abstraction" version = "0.7.1" @@ -9006,6 +9099,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wide" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a1851a719f11d1d2fea40e15c72f6c00de8c142d7ac47c1441cc7e4d0d5bc6" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "widestring" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 449a9ebc51bcbe..3067c39fbd5805 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "ext/fetch", "ext/ffi", "ext/fs", + "ext/geometry", "ext/http", "ext/io", "ext/kv", @@ -81,6 +82,7 @@ deno_crypto = { version = "0.201.0", path = "./ext/crypto" } deno_fetch = { version = "0.211.0", path = "./ext/fetch" } deno_ffi = { version = "0.174.0", path = "./ext/ffi" } deno_fs = { version = "0.97.0", path = "./ext/fs" } +deno_geometry = { version = "0.1.0", path = "./ext/geometry" } deno_http = { version = "0.185.0", path = "./ext/http" } deno_io = { version = "0.97.0", path = "./ext/io" } deno_kv = { version = "0.95.0", path = "./ext/kv" } @@ -236,6 +238,10 @@ opentelemetry_sdk = "0.27.0" hkdf = "0.12.3" rsa = { version = "0.9.3", default-features = false, features = ["std", "pem", "hazmat"] } # hazmat needed for PrehashSigner in ext/node +# geometry +# TODO(petamoriken): Prefer to use glam as well as wgpu, but glam is not sufficient for mutable operations +nalgebra = { version = "0.33.2", default-features = false, features = ["std"] } + # webgpu raw-window-handle = "0.6.0" wgpu-core = "0.21.1" @@ -301,6 +307,8 @@ opt-level = 3 opt-level = 3 [profile.release.package.deno_ffi] opt-level = 3 +[profile.release.package.deno_geometry] +opt-level = 3 [profile.release.package.deno_http] opt-level = 3 [profile.release.package.deno_napi] diff --git a/cli/build.rs b/cli/build.rs index 742f227ec9dc5c..6e1632ce0a8bb6 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -153,6 +153,7 @@ mod ts { op_crate_libs.insert("deno.url", deno_url::get_declaration()); op_crate_libs.insert("deno.web", deno_web::get_declaration()); op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration()); + op_crate_libs.insert("deno.geometry", deno_geometry::get_declaration()); op_crate_libs.insert("deno.webgpu", deno_webgpu_get_declaration()); op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration()); op_crate_libs.insert("deno.webstorage", deno_webstorage::get_declaration()); diff --git a/cli/tsc/dts/lib.deno.shared_globals.d.ts b/cli/tsc/dts/lib.deno.shared_globals.d.ts index a469525270b588..d8ef7794055080 100644 --- a/cli/tsc/dts/lib.deno.shared_globals.d.ts +++ b/cli/tsc/dts/lib.deno.shared_globals.d.ts @@ -11,6 +11,7 @@ /// /// /// +/// /// /// /// diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 868610cb40a535..f8f69a009b5f31 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -102,6 +102,7 @@ pub fn get_types_declaration_file_text() -> String { "deno.webstorage", "deno.canvas", "deno.crypto", + "deno.geometry", "deno.broadcast_channel", "deno.net", "deno.shared_globals", diff --git a/ext/geometry/00_init.js b/ext/geometry/00_init.js new file mode 100644 index 00000000000000..ea5e20870f2c87 --- /dev/null +++ b/ext/geometry/00_init.js @@ -0,0 +1,27 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +import { core } from "ext:core/mod.js"; + +const lazyLoad = core.createLazyLoader("ext:deno_geometry/01_geometry.js"); + +let geometry; + +/** + * @param {(transformList: string, prefix: string) => { matrix: Float64Array, is2D: boolean }} transformListParser + * @param {boolean} enableWindowFeatures + */ +export function createGeometryLoader( + transformListParser, + enableWindowFeatures, +) { + return () => { + if (geometry !== undefined) { + return geometry; + } + + geometry = lazyLoad(); + geometry.init(transformListParser, enableWindowFeatures); + + return geometry; + }; +} diff --git a/ext/geometry/01_geometry.js b/ext/geometry/01_geometry.js new file mode 100644 index 00000000000000..81ed2c5f18c0db --- /dev/null +++ b/ext/geometry/01_geometry.js @@ -0,0 +1,1531 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +import { primordials } from "ext:core/mod.js"; +import { + DOMMatrixInner, + DOMPointInner, + DOMQuadInner, + DOMRectInner, +} from "ext:core/ops"; +const { + ArrayPrototypeJoin, + Float32Array, + Float64Array, + ObjectDefineProperty, + ObjectPrototypeIsPrototypeOf, + Symbol, + SymbolFor, + SymbolIterator, + TypeError, + TypedArrayPrototypeJoin, +} = primordials; + +import { createFilteredInspectProxy } from "ext:deno_console/01_console.js"; +import * as webidl from "ext:deno_webidl/00_webidl.js"; +import { DOMException } from "ext:deno_web/01_dom_exception.js"; + +const _inner = Symbol("[[inner]]"); +// Property to prevent writing values when an immutable instance is changed to +// a mutable instance by Object.setPrototypeOf +// TODO(petamoriken): Implementing resistance to Object.setPrototypeOf in the WebIDL layer +const _writable = Symbol("[[writable]]"); +const _brand = webidl.brand; + +class DOMPointReadOnly { + [_writable] = false; + /** @type {DOMPointInner} */ + [_inner]; + + constructor(x = 0, y = 0, z = 0, w = 1) { + this[_inner] = new DOMPointInner(x, y, z, w); + this[_brand] = _brand; + } + + static fromPoint(other = { __proto__: null }) { + const point = webidl.createBranded(DOMPointReadOnly); + point[_writable] = false; + point[_inner] = DOMPointInner.fromPoint(other); + return point; + } + + get x() { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + return this[_inner].x; + } + + get y() { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + return this[_inner].y; + } + + get z() { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + return this[_inner].z; + } + + get w() { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + return this[_inner].w; + } + + matrixTransform(matrix = { __proto__: null }) { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + let matrixInner; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + matrix !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, matrix) + ) { + matrixInner = matrix[_inner]; + } else { + matrixInner = DOMMatrixInner.fromMatrix(matrix); + } + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = this[_inner].matrixTransform(matrixInner); + return point; + } + + toJSON() { + webidl.assertBranded(this, DOMPointReadOnlyPrototype); + const { x, y, z, w } = this[_inner]; + return { x, y, z, w }; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMPointReadOnlyPrototype, this), + keys: [ + "x", + "y", + "z", + "w", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMPointReadOnly); +const DOMPointReadOnlyPrototype = DOMPointReadOnly.prototype; + +class DOMPoint extends DOMPointReadOnly { + [_writable] = true; + + static fromPoint(other = { __proto__: null }) { + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = DOMPointInner.fromPoint(other); + return point; + } + + get x() { + webidl.assertBranded(this, DOMPointPrototype); + return this[_inner].x; + } + set x(value) { + webidl.assertBranded(this, DOMPointPrototype); + assertWritable(this); + this[_inner].x = value; + } + + get y() { + webidl.assertBranded(this, DOMPointPrototype); + return this[_inner].y; + } + set y(value) { + webidl.assertBranded(this, DOMPointPrototype); + assertWritable(this); + this[_inner].y = value; + } + + get z() { + webidl.assertBranded(this, DOMPointPrototype); + return this[_inner].z; + } + set z(value) { + webidl.assertBranded(this, DOMPointPrototype); + assertWritable(this); + this[_inner].z = value; + } + + get w() { + webidl.assertBranded(this, DOMPointPrototype); + return this[_inner].w; + } + set w(value) { + webidl.assertBranded(this, DOMPointPrototype); + assertWritable(this); + this[_inner].w = value; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMPointPrototype, this), + keys: [ + "x", + "y", + "z", + "w", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMPoint); +const DOMPointPrototype = DOMPoint.prototype; + +class DOMRectReadOnly { + [_writable] = false; + /** @type {DOMRectInner} */ + [_inner]; + + constructor(x = 0, y = 0, width = 0, height = 0) { + this[_inner] = new DOMRectInner(x, y, width, height); + this[_brand] = _brand; + } + + static fromRect(other = { __proto__: null }) { + const rect = webidl.createBranded(DOMRectReadOnly); + rect[_writable] = false; + rect[_inner] = DOMRectInner.fromRect(other); + return rect; + } + + get x() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].x; + } + + get y() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].y; + } + + get width() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].width; + } + + get height() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].height; + } + + get top() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].top; + } + + get right() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].right; + } + + get bottom() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].bottom; + } + + get left() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + return this[_inner].left; + } + + toJSON() { + webidl.assertBranded(this, DOMRectReadOnlyPrototype); + const { x, y, width, height, top, right, bottom, left } = this[_inner]; + return { x, y, width, height, top, right, bottom, left }; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMRectReadOnlyPrototype, this), + keys: [ + "x", + "y", + "width", + "height", + "top", + "right", + "bottom", + "left", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMRectReadOnly); +const DOMRectReadOnlyPrototype = DOMRectReadOnly.prototype; + +class DOMRect extends DOMRectReadOnly { + [_writable] = true; + + static fromRect(other = { __proto__: null }) { + const rect = webidl.createBranded(DOMRect); + rect[_writable] = true; + rect[_inner] = DOMRectInner.fromRect(other); + return rect; + } + + get x() { + webidl.assertBranded(this, DOMRectPrototype); + return this[_inner].x; + } + set x(value) { + webidl.assertBranded(this, DOMRectPrototype); + assertWritable(this); + this[_inner].x = value; + } + + get y() { + webidl.assertBranded(this, DOMRectPrototype); + return this[_inner].y; + } + set y(value) { + webidl.assertBranded(this, DOMRectPrototype); + assertWritable(this); + this[_inner].y = value; + } + + get width() { + webidl.assertBranded(this, DOMRectPrototype); + return this[_inner].width; + } + set width(value) { + webidl.assertBranded(this, DOMRectPrototype); + assertWritable(this); + this[_inner].width = value; + } + + get height() { + webidl.assertBranded(this, DOMRectPrototype); + return this[_inner].height; + } + set height(value) { + webidl.assertBranded(this, DOMRectPrototype); + assertWritable(this); + this[_inner].height = value; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMRectPrototype, this), + keys: [ + "x", + "y", + "width", + "height", + "top", + "right", + "bottom", + "left", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMRect); +const DOMRectPrototype = DOMRect.prototype; + +const _p1 = Symbol("[[p1]]"); +const _p2 = Symbol("[[p2]]"); +const _p3 = Symbol("[[p3]]"); +const _p4 = Symbol("[[p4]]"); + +class DOMQuad { + /** @type {DOMQuadInner} */ + [_inner]; + /** @type {DOMPoint=} */ + [_p1]; + /** @type {DOMPoint=} */ + [_p2]; + /** @type {DOMPoint=} */ + [_p3]; + /** @type {DOMPoint=} */ + [_p4]; + + constructor( + p1 = { __proto__: null }, + p2 = { __proto__: null }, + p3 = { __proto__: null }, + p4 = { __proto__: null }, + ) { + this[_inner] = new DOMQuadInner(p1, p2, p3, p4); + this[_brand] = _brand; + } + + static fromRect(other = { __proto__: null }) { + const quad = webidl.createBranded(DOMQuad); + quad[_inner] = DOMQuadInner.fromRect(other); + quad[_p1] = undefined; + quad[_p2] = undefined; + quad[_p3] = undefined; + quad[_p4] = undefined; + return quad; + } + + static fromQuad(other = { __proto__: null }) { + const quad = webidl.createBranded(DOMQuad); + quad[_inner] = DOMQuadInner.fromQuad(other); + quad[_p1] = undefined; + quad[_p2] = undefined; + quad[_p3] = undefined; + quad[_p4] = undefined; + return quad; + } + + get p1() { + webidl.assertBranded(this, DOMQuadPrototype); + if (this[_p1] !== undefined) { + return this[_p1]; + } + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = this[_inner].p1; + this[_p1] = point; + return point; + } + + get p2() { + webidl.assertBranded(this, DOMQuadPrototype); + if (this[_p2] !== undefined) { + return this[_p2]; + } + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = this[_inner].p2; + this[_p2] = point; + return point; + } + + get p3() { + webidl.assertBranded(this, DOMQuadPrototype); + if (this[_p3] !== undefined) { + return this[_p3]; + } + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = this[_inner].p3; + this[_p3] = point; + return point; + } + + get p4() { + webidl.assertBranded(this, DOMQuadPrototype); + if (this[_p4] !== undefined) { + return this[_p4]; + } + const point = webidl.createBranded(DOMPoint); + point[_writable] = true; + point[_inner] = this[_inner].p4; + this[_p4] = point; + return point; + } + + getBounds() { + webidl.assertBranded(this, DOMQuadPrototype); + const bounds = webidl.createBranded(DOMRect); + bounds[_writable] = true; + bounds[_inner] = this[_inner].getBounds(); + return bounds; + } + + toJSON() { + webidl.assertBranded(this, DOMQuadPrototype); + return { + p1: this[_p1], + p2: this[_p2], + p3: this[_p3], + p4: this[_p4], + }; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMQuadPrototype, this), + keys: [ + "p1", + "p2", + "p3", + "p4", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMQuad); +const DOMQuadPrototype = DOMQuad.prototype; + +class DOMMatrixReadOnly { + [_writable] = false; + /** @type {DOMMatrixInner} */ + [_inner]; + + constructor(init = undefined) { + const prefix = `Failed to construct '${this.constructor.name}'`; + this[_brand] = _brand; + if (init === undefined) { + this[_inner] = DOMMatrixInner.identity(); + } else if ( + webidl.type(init) === "Object" && init[SymbolIterator] !== undefined + ) { + init = webidl.converters["sequence"]( + init, + prefix, + "Argument 1", + ); + initMatrixFromSequence(this, init, prefix); + } else { + init = webidl.converters.DOMString( + init, + prefix, + "Argument 1", + ); + const { matrix, is2D } = parseTransformList(init, prefix); + this[_inner] = new DOMMatrixInner(matrix, is2D); + } + } + + static fromMatrix(other = { __proto__: null }) { + const matrix = webidl.createBranded(DOMMatrixReadOnly); + matrix[_writable] = false; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + other !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, other) + ) { + matrix[_inner] = other[_inner].clone(); + } else { + matrix[_inner] = DOMMatrixInner.fromMatrix(other); + } + return matrix; + } + + static fromFloat32Array(float32) { + const prefix = "Failed to execute 'DOMMatrixReadOnly.fromFloat32Array'"; + webidl.requiredArguments(arguments.length, 1, prefix); + float32 = webidl.converters.Float32Array(float32, prefix, "Argument 1"); + const matrix = webidl.createBranded(DOMMatrixReadOnly); + matrix[_writable] = false; + initMatrixFromSequence(matrix, float32, prefix); + return matrix; + } + + static fromFloat64Array(float64) { + const prefix = "Failed to execute 'DOMMatrixReadOnly.fromFloat64Array'"; + webidl.requiredArguments(arguments.length, 1, prefix); + float64 = webidl.converters.Float64Array(float64, prefix, "Argument 1"); + const matrix = webidl.createBranded(DOMMatrixReadOnly); + matrix[_writable] = false; + initMatrixFromSequence(matrix, float64, prefix); + return matrix; + } + + get a() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].a; + } + + get b() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].b; + } + + get c() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].c; + } + + get d() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].d; + } + + get e() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].e; + } + + get f() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].f; + } + + get m11() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m11; + } + + get m12() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m12; + } + + get m13() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m13; + } + + get m14() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m14; + } + + get m21() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m21; + } + + get m22() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m22; + } + + get m23() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m23; + } + + get m24() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m24; + } + + get m31() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m31; + } + + get m32() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m32; + } + + get m33() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m33; + } + + get m34() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m34; + } + + get m41() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m41; + } + + get m42() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m42; + } + + get m43() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m43; + } + + get m44() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].m44; + } + + get is2D() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].is2D; + } + + get isIdentity() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return this[_inner].isIdentity; + } + + translate(tx = 0, ty = 0, tz = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].translate(tx, ty, tz); + return matrix; + } + + scale( + scaleX = 1, + scaleY = scaleX, + scaleZ = 1, + originX = 0, + originY = 0, + originZ = 0, + ) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + if (originX === 0 && originY === 0 && originZ === 0) { + matrix[_inner] = this[_inner].scaleWithoutOrigin( + scaleX, + scaleY, + scaleZ, + ); + } else { + matrix[_inner] = this[_inner].scaleWithOrigin( + scaleX, + scaleY, + scaleZ, + originX, + originY, + originZ, + ); + } + return matrix; + } + + scaleNonUniform(scaleX = 1, scaleY = 1) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].scaleWithoutOrigin( + scaleX, + scaleY, + 1, + ); + return matrix; + } + + scale3d(scale = 1, originX = 0, originY = 0, originZ = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + if (originX === 0 && originY === 0 && originZ === 0) { + matrix[_inner] = this[_inner].scaleWithoutOrigin( + scale, + scale, + scale, + ); + } else { + matrix[_inner] = this[_inner].scaleWithOrigin( + scale, + scale, + scale, + originX, + originY, + originZ, + ); + } + return matrix; + } + + rotate(rotX = 0, rotY, rotZ) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + if (rotY === undefined && rotZ === undefined) { + rotZ = rotX; + rotX = 0; + rotY = 0; + } else { + rotY = rotY !== undefined ? rotY : 0; + rotZ = rotZ !== undefined ? rotZ : 0; + } + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].rotate( + rotX, + rotY, + rotZ, + ); + return matrix; + } + + rotateFromVector(x = 0, y = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].rotateFromVector(x, y); + return matrix; + } + + rotateAxisAngle(x = 0, y = 0, z = 0, angle = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].rotateAxisAngle( + x, + y, + z, + angle, + ); + return matrix; + } + + skewX(sx = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].skewX(sx); + return matrix; + } + + skewY(sy = 0) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].skewY(sy); + return matrix; + } + + multiply(other = { __proto__: null }) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + let otherInner; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + other !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, other) + ) { + otherInner = other[_inner]; + } else { + otherInner = DOMMatrixInner.fromMatrix(other); + } + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].multiply(otherInner); + return matrix; + } + + flipX() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].flipX(); + return matrix; + } + + flipY() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].flipY(); + return matrix; + } + + inverse() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + matrix[_inner] = this[_inner].inverse(); + return matrix; + } + + transformPoint(point = { __proto__: null }) { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + let pointInner; + // fast path for DOMPoint or DOMPointReadOnly + if ( + point !== null && + ObjectPrototypeIsPrototypeOf(DOMPointReadOnlyPrototype, point) + ) { + pointInner = point[_inner]; + } else { + pointInner = DOMPointInner.fromPoint(point); + } + const result = webidl.createBranded(DOMPoint); + result[_writable] = true; + result[_inner] = this[_inner].transformPoint(pointInner); + return result; + } + + toFloat32Array() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return new Float32Array( + new Float64Array( + this[_inner].toBuffer(), + ), + ); + } + + toFloat64Array() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + return new Float64Array(this[_inner].toBuffer()); + } + + toJSON() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const { + a, + b, + c, + d, + e, + f, + m11, + m12, + m13, + m14, + m21, + m22, + m23, + m24, + m31, + m32, + m33, + m34, + m41, + m42, + m43, + m44, + is2D, + isIdentity, + } = this[_inner]; + return { + a, + b, + c, + d, + e, + f, + m11, + m12, + m13, + m14, + m21, + m22, + m23, + m24, + m31, + m32, + m33, + m34, + m41, + m42, + m43, + m44, + is2D, + isIdentity, + }; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf( + DOMMatrixReadOnlyPrototype, + this, + ), + keys: [ + "a", + "b", + "c", + "d", + "e", + "f", + "m11", + "m12", + "m13", + "m14", + "m21", + "m22", + "m23", + "m24", + "m31", + "m32", + "m33", + "m34", + "m41", + "m42", + "m43", + "m44", + "is2D", + "isIdentity", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMMatrixReadOnly); +const DOMMatrixReadOnlyPrototype = DOMMatrixReadOnly.prototype; + +class DOMMatrix extends DOMMatrixReadOnly { + [_writable] = true; + + static fromMatrix(other = { __proto__: null }) { + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + other !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, other) + ) { + matrix[_inner] = other[_inner].clone(); + } else { + matrix[_inner] = DOMMatrixInner.fromMatrix(other); + } + return matrix; + } + + static fromFloat32Array(float32) { + const prefix = "Failed to execute 'DOMMatrix.fromFloat32Array'"; + webidl.requiredArguments(arguments.length, 1, prefix); + float32 = webidl.converters.Float32Array(float32, prefix, "Argument 1"); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + initMatrixFromSequence(matrix, float32, prefix); + return matrix; + } + + static fromFloat64Array(float64) { + const prefix = "Failed to execute 'DOMMatrix.fromFloat64Array'"; + webidl.requiredArguments(arguments.length, 1, prefix); + float64 = webidl.converters.Float64Array(float64, prefix, "Argument 1"); + const matrix = webidl.createBranded(DOMMatrix); + matrix[_writable] = true; + initMatrixFromSequence(matrix, float64, prefix); + return matrix; + } + + get a() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].a; + } + set a(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].a = value; + } + + get b() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].b; + } + set b(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].b = value; + } + + get c() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].c; + } + set c(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].c = value; + } + + get d() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].d; + } + set d(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].d = value; + } + + get e() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].e; + } + set e(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].e = value; + } + + get f() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].f; + } + set f(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].f = value; + } + + get m11() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m11; + } + set m11(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m11 = value; + } + + get m12() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m12; + } + set m12(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m12 = value; + } + + get m13() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m13; + } + set m13(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m13 = value; + } + + get m14() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m14; + } + set m14(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m14 = value; + } + + get m21() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m21; + } + set m21(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m21 = value; + } + + get m22() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m22; + } + set m22(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m22 = value; + } + + get m23() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m23; + } + set m23(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m23 = value; + } + + get m24() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m24; + } + set m24(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m24 = value; + } + + get m31() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m31; + } + set m31(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m31 = value; + } + + get m32() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m32; + } + set m32(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m32 = value; + } + + get m33() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m33; + } + set m33(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m33 = value; + } + + get m34() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m34; + } + set m34(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m34 = value; + } + + get m41() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m41; + } + set m41(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m41 = value; + } + + get m42() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m42; + } + set m42(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m42 = value; + } + + get m43() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m43; + } + set m43(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m43 = value; + } + + get m44() { + webidl.assertBranded(this, DOMMatrixPrototype); + return this[_inner].m44; + } + set m44(value) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].m44 = value; + } + + multiplySelf(other = { __proto__: null }) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + let otherInner; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + other !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, other) + ) { + otherInner = other[_inner]; + } else { + otherInner = DOMMatrixInner.fromMatrix(other); + } + this[_inner].multiplySelf(otherInner); + return this; + } + + preMultiplySelf(other = { __proto__: null }) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + let otherInner; + // fast path for DOMMatrix or DOMMatrixReadOnly + if ( + other !== null && + ObjectPrototypeIsPrototypeOf(DOMMatrixReadOnlyPrototype, other) + ) { + otherInner = other[_inner]; + } else { + otherInner = DOMMatrixInner.fromMatrix(other); + } + this[_inner].preMultiplySelf(otherInner); + return this; + } + + translateSelf(tx = 0, ty = 0, tz = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].translateSelf(tx, ty, tz); + return this; + } + + scaleSelf( + scaleX = 1, + scaleY = scaleX, + scaleZ = 1, + originX = 0, + originY = 0, + originZ = 0, + ) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + if (originX === 0 && originY === 0 && originZ === 0) { + this[_inner].scaleWithoutOriginSelf(scaleX, scaleY, scaleZ); + } else { + this[_inner].scaleWithOriginSelf( + scaleX, + scaleY, + scaleZ, + originX, + originY, + originZ, + ); + } + return this; + } + + scale3dSelf(scale = 1, originX = 0, originY = 0, originZ = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + if (originX === 0 && originY === 0 && originZ === 0) { + this[_inner].scaleWithoutOriginSelf(scale, scale, scale); + } else { + this[_inner].scaleWithOriginSelf( + scale, + scale, + scale, + originX, + originY, + originZ, + ); + } + return this; + } + + rotateSelf(rotX = 0, rotY, rotZ) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + if (rotY === undefined && rotZ === undefined) { + rotZ = rotX; + rotX = 0; + rotY = 0; + } else { + rotY = rotY !== undefined ? rotY : 0; + rotZ = rotZ !== undefined ? rotZ : 0; + } + this[_inner].rotateSelf( + rotX, + rotY, + rotZ, + ); + return this; + } + + rotateFromVectorSelf(x = 0, y = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].rotateFromVectorSelf(x, y); + return this; + } + + rotateAxisAngleSelf(x = 0, y = 0, z = 0, angle = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].rotateAxisAngleSelf( + x, + y, + z, + angle, + ); + return this; + } + + skewXSelf(sx = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].skewXSelf(sx); + return this; + } + + skewYSelf(sy = 0) { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].skewYSelf(sy); + return this; + } + + invertSelf() { + webidl.assertBranded(this, DOMMatrixPrototype); + assertWritable(this); + this[_inner].invertSelf(); + return this; + } + + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { + return inspect( + createFilteredInspectProxy({ + object: this, + evaluate: ObjectPrototypeIsPrototypeOf(DOMMatrixPrototype, this), + keys: [ + "a", + "b", + "c", + "d", + "e", + "f", + "m11", + "m12", + "m13", + "m14", + "m21", + "m22", + "m23", + "m24", + "m31", + "m32", + "m33", + "m34", + "m41", + "m42", + "m43", + "m44", + "is2D", + "isIdentity", + ], + }), + inspectOptions, + ); + } +} + +webidl.configureInterface(DOMMatrix); +const DOMMatrixPrototype = DOMMatrix.prototype; + +/** + * TODO(petamoriken): Support this by updating WebIDL's brand features + * @param {DOMRect | DOMPoint | DOMMatrix} self + */ +function assertWritable(self) { + if (self[_writable] !== true) { + throw new TypeError("Illegal invocation"); + } +} + +/** + * @param {object} target + * @param {number[] | Float32Array | Float64Array} seq + * @param {string} prefix + */ +function initMatrixFromSequence(target, seq, prefix) { + if (seq.length === 6) { + const { 0: a, 1: b, 2: c, 3: d, 4: e, 5: f } = seq; + // deno-fmt-ignore + target[_inner] = new DOMMatrixInner(new Float64Array([ + a, b, 0, 0, + c, d, 0, 0, + 0, 0, 1, 0, + e, f, 0, 1, + ]), /* is2D */ true); + } else if (seq.length === 16) { + target[_inner] = new DOMMatrixInner( + new Float64Array(seq), + /* is2D */ false, + ); + } else { + throw new TypeError( + `${prefix}: The sequence must contain 6 elements for a 2D matrix or 16 elements for a 3D matrix`, + ); + } +} + +/** + * CSS parser + * @type {((transformList: string, prefix: string) => { matrix: Float64Array, is2D: boolean })} + */ +let parseTransformList; + +/** + * @param {(transformList: string, prefix: string) => { matrix: Float64Array, is2D: boolean }} transformListParser + * @param {boolean} enableWindowFeatures + */ +function init(transformListParser, enableWindowFeatures) { + parseTransformList = transformListParser; + + if (enableWindowFeatures) { + // https://drafts.fxtf.org/geometry/#dommatrixreadonly-stringification-behavior + ObjectDefineProperty(DOMMatrixReadOnlyPrototype, "toString", { + __proto__: null, + value: function toString() { + webidl.assertBranded(this, DOMMatrixReadOnlyPrototype); + const inner = this[_inner]; + if (!inner.isFinite) { + throw new DOMException( + "Failed to execute 'toString' on 'DOMMatrixReadOnly': Cannot be serialized with NaN or Infinity values", + "InvalidStateError", + ); + } + if (inner.is2D) { + return `matrix(${ + ArrayPrototypeJoin([ + inner.a, + inner.b, + inner.c, + inner.d, + inner.e, + inner.f, + ], ", ") + })`; + } else { + return `matrix3d(${ + TypedArrayPrototypeJoin(new Float64Array(inner.toBuffer()), ", ") + })`; + } + }, + writable: true, + enumerable: true, + configurable: true, + }); + + // https://drafts.fxtf.org/geometry/#dom-dommatrix-setmatrixvalue + ObjectDefineProperty(DOMMatrixPrototype, "setMatrixValue", { + __proto__: null, + value: function setMatrixValue(transformList) { + webidl.assertBranded(this, DOMMatrixPrototype); + const prefix = "Failed to execute 'setMatrixValue' on 'DOMMatrix'"; + webidl.requiredArguments(arguments.length, 1, prefix); + transformList = webidl.converters.DOMString( + transformList, + prefix, + "Argument 1", + ); + const { matrix, is2D } = parseTransformList(transformList, prefix); + this[_inner] = new DOMMatrixInner(matrix, is2D); + }, + writable: true, + enumerable: true, + configurable: true, + }); + } +} + +export { + DOMMatrix, + DOMMatrixPrototype, + DOMMatrixReadOnly, + DOMMatrixReadOnlyPrototype, + DOMPoint, + DOMPointPrototype, + DOMPointReadOnly, + DOMPointReadOnlyPrototype, + DOMQuad, + DOMQuadPrototype, + DOMRect, + DOMRectPrototype, + DOMRectReadOnly, + DOMRectReadOnlyPrototype, + init, +}; diff --git a/ext/geometry/Cargo.toml b/ext/geometry/Cargo.toml new file mode 100644 index 00000000000000..eeca9d2f4a0076 --- /dev/null +++ b/ext/geometry/Cargo.toml @@ -0,0 +1,20 @@ +# Copyright 2018-2025 the Deno authors. MIT license. + +[package] +name = "deno_geometry" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" +repository.workspace = true +description = "Geometry Interfaces Module API implementation for Deno" + +[lib] +path = "lib.rs" + +[dependencies] +deno_core.workspace = true +deno_error.workspace = true +nalgebra.workspace = true +thiserror.workspace = true diff --git a/ext/geometry/README.md b/ext/geometry/README.md new file mode 100644 index 00000000000000..8c2f421b10d5e4 --- /dev/null +++ b/ext/geometry/README.md @@ -0,0 +1,98 @@ +# deno_geometry + +This crate implements the Geometry Interfaces Module API. + +Spec: https://drafts.fxtf.org/geometry/ + +## Usage Example + +From javascript, include the extension's source: + +```javascript +import { core } from "ext:core/mod.js"; +import { createGeometryLoader } from "ext:deno_geometry/00_init.js"; +``` + +For environments that do not have a CSS `` parser, such as Web +Worker, configure as follows: + +```javascript +const loadGeometry = createGeometryLoader((_transformList, prefix) => { + throw new TypeError( + `${prefix}: Cannot parse CSS on Workers`, + ); +}, /* enableWindowFeatures */ false); +``` + +On the other hand, in environments with a CSS `` parser, you can +configure as follows: + +```javascript +const loadGeometry = createGeometryLoader((transformList, prefix) => { + try { + // parse by yourself + const { sequence, is2D } = parse(transformList); + return { + matrix: new Float64Array(sequence), + is2D, + }; + } catch { + throw new TypeError( + `${prefix}: Invalid string: ${transformList}`, + ); + } +}, /* enableWindowFeatures */ true); +``` + +Then define to globalThis: + +```javascript +Object.defineProperties(globalThis, { + DOMMatrix: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrix, + loadGeometry, + ), + DOMMatrixReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrixReadOnly, + loadGeometry, + ), + DOMPoint: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPoint, + loadGeometry, + ), + DOMPointReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPointReadOnly, + loadGeometry, + ), + DOMQuad: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMQuad, + loadGeometry, + ), + DOMRect: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRect, + loadGeometry, + ), + DOMRectReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRectReadOnly, + loadGeometry, + ), +}); +``` + +Then from rust, provide: `deno_geometry::deno_geometry::init_ops_and_esm()` in +the `extensions` field of your `RuntimeOptions` + +## Dependencies + +- **deno_webidl**: Provided by the `deno_webidl` crate +- **deno_web**: Provided by the `deno_web` crate +- **deno_console**: Provided by the `deno_console` crate + +## Provided ops + +Following ops are provided, which can be accessed through `Deno.ops`: + +- DOMMatrixInner +- DOMPointInner +- DOMQuadInner +- DOMRectInner diff --git a/ext/geometry/lib.deno_geometry.d.ts b/ext/geometry/lib.deno_geometry.d.ts new file mode 100644 index 00000000000000..800993ee4f3976 --- /dev/null +++ b/ext/geometry/lib.deno_geometry.d.ts @@ -0,0 +1,602 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +// deno-lint-ignore-file no-var + +/// +/// + +/** @category Geometry Interfaces Module API */ +interface DOMMatrix2DInit { + a?: number; + b?: number; + c?: number; + d?: number; + e?: number; + f?: number; + m11?: number; + m12?: number; + m21?: number; + m22?: number; + m41?: number; + m42?: number; +} + +/** @category Geometry Interfaces Module API */ +interface DOMMatrixInit extends DOMMatrix2DInit { + is2D?: boolean; + m13?: number; + m14?: number; + m23?: number; + m24?: number; + m31?: number; + m32?: number; + m33?: number; + m34?: number; + m43?: number; + m44?: number; +} + +/** + * A 4×4 matrix (column-major order), suitable for 2D and 3D operations including rotation and translation. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMMatrix) + * + * ``` + * | m11 m21 m31 m41 | + * | m12 m22 m32 m42 | + * | m13 m23 m33 m43 | + * | m14 m24 m34 m44 | + * ``` + * + * @category Geometry Interfaces Module API + */ +interface DOMMatrix extends DOMMatrixReadOnly { + a: number; + b: number; + c: number; + d: number; + e: number; + f: number; + m11: number; + m12: number; + m13: number; + m14: number; + m21: number; + m22: number; + m23: number; + m24: number; + m31: number; + m32: number; + m33: number; + m34: number; + m41: number; + m42: number; + m43: number; + m44: number; + /** + * Modifies the matrix by inverting it. + * If the matrix can't be inverted, its components are all set to `NaN`, and is2D property is set to `false`. + */ + invertSelf(): DOMMatrix; + /** + * Modifies the matrix by post-multiplying it with the specified DOMMatrix. + * This is equivalent to the dot product `A⋅B`, where matrix `A` is the source matrix and `B` is the matrix given as an input to the method. + * + * @param other + */ + multiplySelf(other?: DOMMatrixInit): DOMMatrix; + /** + * Modifies the matrix by pre-multiplying it with the specified DOMMatrix. + * This is equivalent to the dot product B⋅A, where matrix `A` is the source matrix and `B` is the matrix given as an input to the method. + * + * @param other + */ + preMultiplySelf(other?: DOMMatrixInit): DOMMatrix; + /** + * Modifies the matrix by rotating it by the specified angle around the given vector. + * + * @param x + * @param y + * @param z + * @param angle in degrees + */ + rotateAxisAngleSelf( + x?: number, + y?: number, + z?: number, + angle?: number, + ): DOMMatrix; + /** + * Modifies the matrix by rotating it by the angle between the specified vector and `(1, 0)`. + * + * @param x + * @param y + */ + rotateFromVectorSelf(x?: number, y?: number): DOMMatrix; + /** + * Modifies the matrix by rotating itself around each axis by the specified number of degrees. + * + * @param rotZ yaw angle in degrees + */ + rotateSelf(rotZ?: number): DOMMatrix; + /** + * Modifies the matrix by rotating itself around each axis by the specified number of degrees. + * + * @param rotX roll angle in degrees + * @param rotY pitch angle in degrees + * @param rotZ yaw angle in degrees + */ + rotateSelf(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix; + /** + * Modifies the matrix by applying the specified scaling factor to all three axes, centered on the given origin. + * + * @param scale + * @param originX + * @param originY + * @param originZ + */ + scale3dSelf( + scale?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + /** + * Modifies the matrix by applying the specified scaling factors, with the center located at the specified origin. Also returns itself. + * By default, the X and Z axes are scaled by `1` and the Y axis is given the same scaling value as the X axis. + * The default origin is `(0, 0, 0)`. + * + * @param scaleX + * @param scaleY + * @param scaleZ + * @param originX + * @param originY + * @param originZ + */ + scaleSelf( + scaleX?: number, + scaleY?: number, + scaleZ?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + /** + * NOTE: Not available in Worker + * + * Replaces the contents of the matrix with the matrix described by the specified transform or transforms. + * + * @param transformList + */ + setMatrixValue(transformList: string): DOMMatrix; + /** + * Modifies the matrix by applying the specified skew transformation along the X-axis. + * + * @param sx in degrees + */ + skewXSelf(sx?: number): DOMMatrix; + /** + * Modifies the matrix by applying the specified skew transformation along the Y-axis. + * + * @param sy in degrees + */ + skewYSelf(sy?: number): DOMMatrix; + /** + * Modifies the matrix by applying the specified vector. The default vector is `(0, 0, 0)`. + * + * @param tx + * @param ty + * @param tz + */ + translateSelf(tx?: number, ty?: number, tz?: number): DOMMatrix; +} + +/** + * A 4×4 matrix (column-major order), suitable for 2D and 3D operations including rotation and translation. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMMatrix) + * + * ``` + * | m11 m21 m31 m41 | + * | m12 m22 m32 m42 | + * | m13 m23 m33 m43 | + * | m14 m24 m34 m44 | + * ``` + * + * @category Geometry Interfaces Module API + */ +declare var DOMMatrix: { + prototype: DOMMatrix; + new (init?: number[]): DOMMatrix; + new (init: DOMMatrix | DOMMatrixReadOnly): DOMMatrix; + /** NOTE: Not available in Worker */ + new (init: string): DOMMatrix; + fromFloat32Array(array32: Float32Array): DOMMatrix; + fromFloat64Array(array64: Float64Array): DOMMatrix; + fromMatrix(other?: DOMMatrixInit): DOMMatrix; +}; + +/** + * A read-only 4×4 matrix (column-major order), suitable for 2D and 3D operations including rotation and translation. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMMatrixReadOnly) + * + * ``` + * | m11 m21 m31 m41 | + * | m12 m22 m32 m42 | + * | m13 m23 m33 m43 | + * | m14 m24 m34 m44 | + * ``` + * + * @category Geometry Interfaces Module API + */ +interface DOMMatrixReadOnly { + readonly a: number; + readonly b: number; + readonly c: number; + readonly d: number; + readonly e: number; + readonly f: number; + readonly is2D: boolean; + readonly isIdentity: boolean; + readonly m11: number; + readonly m12: number; + readonly m13: number; + readonly m14: number; + readonly m21: number; + readonly m22: number; + readonly m23: number; + readonly m24: number; + readonly m31: number; + readonly m32: number; + readonly m33: number; + readonly m34: number; + readonly m41: number; + readonly m42: number; + readonly m43: number; + readonly m44: number; + /** Returns a new `DOMMatrix` created by flipping the source matrix around its X-axis. */ + flipX(): DOMMatrix; + /** Returns a new `DOMMatrix` created by flipping the source matrix around its Y-axis. */ + flipY(): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by inverting the source matrix. + * If the matrix cannot be inverted, the new matrix's components are all set to `NaN` and its is2D property is set to `false`. + */ + inverse(): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by computing the dot product of the source matrix and the specified matrix: `A⋅B`. + * + * @param other + */ + multiply(other?: DOMMatrixInit): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by rotating the source matrix around each of its axes by the specified number of degrees. + * + * @param rotZ yaw angle in degrees + */ + rotate(rotZ?: number): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by rotating the source matrix around each of its axes by the specified number of degrees. + * + * @param rotX roll angle in degrees + * @param rotY pitch angle in degrees + * @param rotZ yaw angle in degrees + */ + rotate(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix; + /** + * Returns a new DOMMatrix created by rotating the source matrix by the given angle around the specified vector. + * + * @param x + * @param y + * @param z + * @param angle in degrees + */ + rotateAxisAngle( + x?: number, + y?: number, + z?: number, + angle?: number, + ): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by rotating the source matrix by the angle between the specified vector and `(1, 0)`. + * + * @param x + * @param y + */ + rotateFromVector(x?: number, y?: number): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by scaling the source matrix by the amount specified for each axis, centered on the given origin. + * By default, the X and Z axes are scaled by `1` and the Y axis is given the same scaling value as the X axis. + * The default origin is `(0, 0, 0)`. + * + * @param scaleX + * @param scaleY + * @param scaleZ + * @param originX + * @param originY + * @param originZ + */ + scale( + scaleX?: number, + scaleY?: number, + scaleZ?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by scaling the source 3D matrix by the given factor along all its axes, centered on the specified origin point. + * The default origin is `(0, 0, 0)`. + * + * @param scale + * @param originX + * @param originY + * @param originZ + */ + scale3d( + scale?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + /** + * Returns a new `DOMMatrix` created by applying the specified scaling on the X, Y, and Z axes, centered at the given origin. + * By default, the X and Y axes' scaling factors are both `1`. + * + * @deprecated Supported for legacy reasons to be compatible with `SVGMatrix` as defined in SVG 1.1. Use `scale()` instead. + * + * @param scaleX + * @param scaleY + */ + scaleNonUniform(scaleX?: number, scaleY?: number): DOMMatrix; + /** + * Returns a new DOMMatrix created by applying the specified skew transformation to the source matrix along its X-axis. + * + * @param sx in degrees + */ + skewX(sx?: number): DOMMatrix; + /** + * Returns a new DOMMatrix created by applying the specified skew transformation to the source matrix along its Y-axis. + * + * @param sy in degrees + */ + skewY(sy?: number): DOMMatrix; + toFloat32Array(): Float32Array; + toFloat64Array(): Float64Array; + toJSON(): { + a: number; + b: number; + c: number; + d: number; + e: number; + f: number; + is2D: boolean; + isIdentity: boolean; + m11: number; + m12: number; + m13: number; + m14: number; + m21: number; + m22: number; + m23: number; + m24: number; + m31: number; + m32: number; + m33: number; + m34: number; + m41: number; + m42: number; + m43: number; + m44: number; + }; + transformPoint(point?: DOMPointInit): DOMPoint; + translate(tx?: number, ty?: number, tz?: number): DOMMatrix; + /** NOTE: Not available in Worker */ + toString(): string; +} + +/** + * A read-only 4×4 matrix (column-major order), suitable for 2D and 3D operations including rotation and translation. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMMatrixReadOnly) + * + * ``` + * | m11 m21 m31 m41 | + * | m12 m22 m32 m42 | + * | m13 m23 m33 m43 | + * | m14 m24 m34 m44 | + * ``` + * + * @category Geometry Interfaces Module API + */ +declare var DOMMatrixReadOnly: { + prototype: DOMMatrixReadOnly; + new (init?: number[]): DOMMatrixReadOnly; + new (init: DOMMatrix | DOMMatrixReadOnly): DOMMatrixReadOnly; + /** Not available in Worker */ + new (init: string): DOMMatrixReadOnly; + fromFloat32Array(array32: Float32Array): DOMMatrixReadOnly; + fromFloat64Array(array64: Float64Array): DOMMatrixReadOnly; + fromMatrix(other?: DOMMatrixInit): DOMMatrixReadOnly; +}; + +/** @category Geometry Interfaces Module API */ +interface DOMPointInit { + w?: number; + x?: number; + y?: number; + z?: number; +} + +/** + * A object represents a 2D or 3D point in a coordinate system; it includes values for the coordinates in up to three dimensions, as well as an optional perspective value. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMPoint) + * + * @category Geometry Interfaces Module API + */ +interface DOMPoint extends DOMPointReadOnly { + w: number; + x: number; + y: number; + z: number; +} + +/** + * A object represents a 2D or 3D point in a coordinate system; it includes values for the coordinates in up to three dimensions, as well as an optional perspective value. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMPoint) + * + * @category Geometry Interfaces Module API + */ +declare var DOMPoint: { + prototype: DOMPoint; + new (x?: number, y?: number, z?: number, w?: number): DOMPoint; + fromPoint(other?: DOMPointInit): DOMPoint; +}; + +/** + * A read-only object represents a 2D or 3D point in a coordinate system; it includes values for the coordinates in up to three dimensions, as well as an optional perspective value. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMPointReadOnly) + * + * @category Geometry Interfaces Module API + */ +interface DOMPointReadOnly { + readonly w: number; + readonly x: number; + readonly y: number; + readonly z: number; + matrixTransform(matrix?: DOMMatrixInit): DOMPoint; + toJSON(): { + w: number; + x: number; + y: number; + z: number; + }; +} + +/** + * A read-only object represents a 2D or 3D point in a coordinate system; it includes values for the coordinates in up to three dimensions, as well as an optional perspective value. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMPointReadOnly) + * + * @category Geometry Interfaces Module API + */ +declare var DOMPointReadOnly: { + prototype: DOMPointReadOnly; + new (x?: number, y?: number, z?: number, w?: number): DOMPointReadOnly; + fromPoint(other?: DOMPointInit): DOMPointReadOnly; +}; + +/** @category Geometry Interfaces Module API */ +interface DOMQuadInit { + p1?: DOMPointInit; + p2?: DOMPointInit; + p3?: DOMPointInit; + p4?: DOMPointInit; +} + +/** + * A collection of four DOMPoints defining the corners of an arbitrary quadrilateral. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMQuad) + * + * @category Geometry Interfaces Module API + */ +interface DOMQuad { + readonly p1: DOMPoint; + readonly p2: DOMPoint; + readonly p3: DOMPoint; + readonly p4: DOMPoint; + getBounds(): DOMRect; + toJSON(): { + p1: DOMPoint; + p2: DOMPoint; + p3: DOMPoint; + p4: DOMPoint; + }; +} + +/** + * A collection of four DOMPoints defining the corners of an arbitrary quadrilateral. + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMQuad) + * + * @category Geometry Interfaces Module API + */ +declare var DOMQuad: { + prototype: DOMQuad; + new ( + p1?: DOMPointInit, + p2?: DOMPointInit, + p3?: DOMPointInit, + p4?: DOMPointInit, + ): DOMQuad; + fromQuad(other?: DOMQuadInit): DOMQuad; + fromRect(other?: DOMRectInit): DOMQuad; +}; + +/** @category Geometry Interfaces Module API */ +interface DOMRectInit { + height?: number; + width?: number; + x?: number; + y?: number; +} + +/** + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMRect) + * + * @category Geometry Interfaces Module API + */ +interface DOMRect extends DOMRectReadOnly { + height: number; + width: number; + x: number; + y: number; +} + +/** + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMRect) + * + * @category Geometry Interfaces Module API + */ +declare var DOMRect: { + prototype: DOMRect; + new (x?: number, y?: number, width?: number, height?: number): DOMRect; + fromRect(other?: DOMRectInit): DOMRect; +}; + +/** + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMRectReadOnly) + * + * @category Geometry Interfaces Module API + */ +interface DOMRectReadOnly { + readonly bottom: number; + readonly height: number; + readonly left: number; + readonly right: number; + readonly top: number; + readonly width: number; + readonly x: number; + readonly y: number; + toJSON(): { + bottom: number; + height: number; + left: number; + right: number; + top: number; + width: number; + x: number; + y: number; + }; +} + +/** + * [MDN](https://developer.mozilla.org/docs/Web/API/DOMRectReadOnly) + * + * @category Geometry Interfaces Module API + */ +declare var DOMRectReadOnly: { + prototype: DOMRectReadOnly; + new ( + x?: number, + y?: number, + width?: number, + height?: number, + ): DOMRectReadOnly; + fromRect(other?: DOMRectInit): DOMRectReadOnly; +}; diff --git a/ext/geometry/lib.rs b/ext/geometry/lib.rs new file mode 100644 index 00000000000000..b12b9a24a502ca --- /dev/null +++ b/ext/geometry/lib.rs @@ -0,0 +1,1559 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::Cell; +use std::cell::RefCell; +use std::mem; +use std::path::PathBuf; +use std::slice; + +use deno_core::cppgc; +use deno_core::cppgc::SameObject; +use deno_core::op2; +use deno_core::v8; +use deno_core::webidl; +use deno_core::GarbageCollected; +use deno_core::WebIDL; +use nalgebra::Matrix3; +use nalgebra::Matrix4; +use nalgebra::Matrix4x2; +use nalgebra::Matrix4x3; +use nalgebra::Rotation3; +use nalgebra::UnitVector3; +use nalgebra::Vector3; +use nalgebra::Vector4; + +deno_core::extension!( + deno_geometry, + deps = [deno_webidl, deno_web, deno_console], + objects = [DOMPointInner, DOMRectInner, DOMQuadInner, DOMMatrixInner], + esm = ["00_init.js"], + lazy_loaded_esm = ["01_geometry.js"], +); + +pub fn get_declaration() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_geometry.d.ts") +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum GeometryError { + #[class(type)] + #[error("Inconsistent 2d matrix value")] + Inconsistent2DMatrix, +} + +#[derive(WebIDL, Debug)] +#[webidl(dictionary)] +pub struct DOMPointInit { + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + x: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + y: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + z: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(1.0))] + w: webidl::UnrestrictedDouble, +} + +#[derive(Debug)] +pub struct DOMPointInner { + inner: RefCell>, +} + +impl GarbageCollected for DOMPointInner {} + +#[op2] +impl DOMPointInner { + #[constructor] + #[cppgc] + pub fn constructor( + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + #[webidl] z: webidl::UnrestrictedDouble, + #[webidl] w: webidl::UnrestrictedDouble, + ) -> DOMPointInner { + DOMPointInner { + inner: RefCell::new(Vector4::new(*x, *y, *z, *w)), + } + } + + #[reentrant] + #[static_method] + #[cppgc] + pub fn from_point(#[webidl] init: DOMPointInit) -> DOMPointInner { + DOMPointInner { + inner: RefCell::new(Vector4::new(*init.x, *init.y, *init.z, *init.w)), + } + } + + #[fast] + #[getter] + pub fn x(&self) -> f64 { + self.inner.borrow().x + } + + #[setter] + pub fn x(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.inner.borrow_mut().x = *value + } + + #[fast] + #[getter] + pub fn y(&self) -> f64 { + self.inner.borrow().y + } + + #[setter] + pub fn y(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.inner.borrow_mut().y = *value + } + + #[fast] + #[getter] + pub fn z(&self) -> f64 { + self.inner.borrow().z + } + + #[setter] + pub fn z(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.inner.borrow_mut().z = *value + } + + #[fast] + #[getter] + pub fn w(&self) -> f64 { + self.inner.borrow().w + } + + #[setter] + pub fn w(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.inner.borrow_mut().w = *value + } + + #[cppgc] + pub fn matrix_transform( + &self, + #[cppgc] matrix: &DOMMatrixInner, + ) -> DOMPointInner { + let out = DOMPointInner { + inner: RefCell::new(Vector4::zeros()), + }; + matrix_transform_point(matrix, self, &out); + out + } +} + +#[derive(WebIDL, Debug)] +#[webidl(dictionary)] +pub struct DOMRectInit { + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + x: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + y: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + width: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + height: webidl::UnrestrictedDouble, +} + +#[derive(Debug)] +pub struct DOMRectInner { + x: Cell, + y: Cell, + width: Cell, + height: Cell, +} + +impl GarbageCollected for DOMRectInner {} + +#[op2] +impl DOMRectInner { + #[constructor] + #[cppgc] + pub fn constructor( + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + #[webidl] width: webidl::UnrestrictedDouble, + #[webidl] height: webidl::UnrestrictedDouble, + ) -> DOMRectInner { + DOMRectInner { + x: Cell::new(*x), + y: Cell::new(*y), + width: Cell::new(*width), + height: Cell::new(*height), + } + } + + #[reentrant] + #[static_method] + #[cppgc] + pub fn from_rect(#[webidl] init: DOMRectInit) -> DOMRectInner { + DOMRectInner { + x: Cell::new(*init.x), + y: Cell::new(*init.y), + width: Cell::new(*init.width), + height: Cell::new(*init.height), + } + } + + #[fast] + #[getter] + pub fn x(&self) -> f64 { + self.x.get() + } + + #[setter] + pub fn x(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.x.set(*value) + } + + #[fast] + #[getter] + pub fn y(&self) -> f64 { + self.y.get() + } + + #[setter] + pub fn y(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.y.set(*value) + } + + #[fast] + #[getter] + pub fn width(&self) -> f64 { + self.width.get() + } + + #[setter] + pub fn width(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.width.set(*value) + } + + #[fast] + #[getter] + pub fn height(&self) -> f64 { + self.height.get() + } + + #[setter] + pub fn height(&self, #[webidl] value: webidl::UnrestrictedDouble) { + self.height.set(*value) + } + + #[fast] + #[getter] + pub fn top(&self) -> f64 { + let y = self.y.get(); + let height = self.height.get(); + minimum(y, y + height) + } + + #[fast] + #[getter] + pub fn right(&self) -> f64 { + let x = self.x.get(); + let width = self.width.get(); + maximum(x, x + width) + } + + #[fast] + #[getter] + pub fn bottom(&self) -> f64 { + let y = self.y.get(); + let height = self.height.get(); + maximum(y, y + height) + } + + #[fast] + #[getter] + pub fn left(&self) -> f64 { + let x = self.x.get(); + let width = self.width.get(); + minimum(x, x + width) + } +} + +#[derive(WebIDL, Debug)] +#[webidl(dictionary)] +pub struct DOMQuadInit { + p1: DOMPointInit, + p2: DOMPointInit, + p3: DOMPointInit, + p4: DOMPointInit, +} + +pub struct DOMQuadInner { + p1: SameObject, + p2: SameObject, + p3: SameObject, + p4: SameObject, +} + +impl GarbageCollected for DOMQuadInner {} + +#[op2] +impl DOMQuadInner { + #[constructor] + #[reentrant] + #[cppgc] + pub fn constructor( + scope: &mut v8::HandleScope, + #[webidl] p1: DOMPointInit, + #[webidl] p2: DOMPointInit, + #[webidl] p3: DOMPointInit, + #[webidl] p4: DOMPointInit, + ) -> DOMQuadInner { + #[inline] + fn from_point( + scope: &mut v8::HandleScope, + point: DOMPointInit, + ) -> SameObject { + let obj = SameObject::new(); + obj.get(scope, |_| DOMPointInner { + inner: RefCell::new(Vector4::new( + *point.x, *point.y, *point.z, *point.w, + )), + }); + obj + } + + DOMQuadInner { + p1: from_point(scope, p1), + p2: from_point(scope, p2), + p3: from_point(scope, p3), + p4: from_point(scope, p4), + } + } + + #[reentrant] + #[static_method] + #[cppgc] + pub fn from_rect( + scope: &mut v8::HandleScope, + #[webidl] rect: DOMRectInit, + ) -> DOMQuadInner { + #[inline] + fn create_point( + scope: &mut v8::HandleScope, + x: f64, + y: f64, + z: f64, + w: f64, + ) -> SameObject { + let obj = SameObject::new(); + obj.get(scope, |_| DOMPointInner { + inner: RefCell::new(Vector4::new(x, y, z, w)), + }); + obj + } + + let DOMRectInit { + x, + y, + width, + height, + } = rect; + DOMQuadInner { + p1: create_point(scope, *x, *y, 0.0, 1.0), + p2: create_point(scope, *x + *width, *y, 0.0, 1.0), + p3: create_point(scope, *x + *width, *y + *height, 0.0, 1.0), + p4: create_point(scope, *x, *y + *height, 0.0, 1.0), + } + } + + #[reentrant] + #[static_method] + #[cppgc] + pub fn from_quad( + scope: &mut v8::HandleScope, + #[webidl] quad: DOMQuadInit, + ) -> DOMQuadInner { + #[inline] + fn from_point( + scope: &mut v8::HandleScope, + point: DOMPointInit, + ) -> SameObject { + let obj = SameObject::new(); + obj.get(scope, |_| DOMPointInner { + inner: RefCell::new(Vector4::new( + *point.x, *point.y, *point.z, *point.w, + )), + }); + obj + } + + DOMQuadInner { + p1: from_point(scope, quad.p1), + p2: from_point(scope, quad.p2), + p3: from_point(scope, quad.p3), + p4: from_point(scope, quad.p4), + } + } + + #[getter] + #[global] + pub fn p1(&self, scope: &mut v8::HandleScope) -> v8::Global { + self.p1.get(scope, |_| unreachable!()) + } + + #[getter] + #[global] + pub fn p2(&self, scope: &mut v8::HandleScope) -> v8::Global { + self.p2.get(scope, |_| unreachable!()) + } + + #[getter] + #[global] + pub fn p3(&self, scope: &mut v8::HandleScope) -> v8::Global { + self.p3.get(scope, |_| unreachable!()) + } + + #[getter] + #[global] + pub fn p4(&self, scope: &mut v8::HandleScope) -> v8::Global { + self.p4.get(scope, |_| unreachable!()) + } + + #[cppgc] + pub fn get_bounds(&self, scope: &mut v8::HandleScope) -> DOMRectInner { + #[inline] + fn get_ptr( + scope: &mut v8::HandleScope, + value: &SameObject, + ) -> cppgc::Ptr { + let value = value.get(scope, |_| unreachable!()); + let value = v8::Local::new(scope, value); + cppgc::try_unwrap_cppgc_object::(scope, value.cast()) + .unwrap() + } + + let p1 = get_ptr(scope, &self.p1); + let p2 = get_ptr(scope, &self.p2); + let p3 = get_ptr(scope, &self.p3); + let p4 = get_ptr(scope, &self.p4); + let p1 = *p1.inner.borrow(); + let p2 = *p2.inner.borrow(); + let p3 = *p3.inner.borrow(); + let p4 = *p4.inner.borrow(); + let left = minimum(minimum(p1.x, p2.x), minimum(p3.x, p4.x)); + let top = minimum(minimum(p1.y, p2.y), minimum(p3.y, p4.y)); + let right = maximum(maximum(p1.x, p2.x), maximum(p3.x, p4.x)); + let bottom = maximum(maximum(p1.y, p2.y), maximum(p3.y, p4.y)); + DOMRectInner { + x: Cell::new(left), + y: Cell::new(top), + width: Cell::new(right - left), + height: Cell::new(bottom - top), + } + } +} + +#[derive(WebIDL, Debug)] +#[webidl(dictionary)] +pub struct DOMMatrixInit { + #[webidl(default = None)] + a: Option, + #[webidl(default = None)] + b: Option, + #[webidl(default = None)] + c: Option, + #[webidl(default = None)] + d: Option, + #[webidl(default = None)] + e: Option, + #[webidl(default = None)] + f: Option, + #[webidl(default = None)] + m11: Option, + #[webidl(default = None)] + m12: Option, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m13: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m14: webidl::UnrestrictedDouble, + #[webidl(default = None)] + m21: Option, + #[webidl(default = None)] + m22: Option, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m23: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m24: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m31: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m32: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(1.0))] + m33: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m34: webidl::UnrestrictedDouble, + #[webidl(default = None)] + m41: Option, + #[webidl(default = None)] + m42: Option, + #[webidl(default = webidl::UnrestrictedDouble(0.0))] + m43: webidl::UnrestrictedDouble, + #[webidl(default = webidl::UnrestrictedDouble(1.0))] + m44: webidl::UnrestrictedDouble, + #[webidl(default = None)] + is_2d: Option, +} + +#[derive(Debug, Clone)] +pub struct DOMMatrixInner { + inner: RefCell>, + is_2d: Cell, +} + +impl GarbageCollected for DOMMatrixInner {} + +/* + * NOTE: column-major order + * + * For a 2D 3x2 matrix, the index of properties in + * | a c 0 e | | 0 4 _ 12 | + * | b d 0 f | | 1 5 _ 13 | + * | 0 0 1 0 | is | _ _ _ _ | + * | 0 0 0 1 | | _ _ _ _ | + */ +const INDEX_A: usize = 0; +const INDEX_B: usize = 1; +const INDEX_C: usize = 4; +const INDEX_D: usize = 5; +const INDEX_E: usize = 12; +const INDEX_F: usize = 13; + +/* + * NOTE: column-major order + * + * The index of properties in + * | m11 m21 m31 m41 | | 0 4 8 12 | + * | m12 m22 m32 m42 | | 1 5 9 13 | + * | m13 m23 m33 m43 | is | 2 6 10 14 | + * | m14 m24 m34 m44 | | 3 7 11 15 | + */ +const INDEX_M11: usize = 0; +const INDEX_M12: usize = 1; +const INDEX_M13: usize = 2; +const INDEX_M14: usize = 3; +const INDEX_M21: usize = 4; +const INDEX_M22: usize = 5; +const INDEX_M23: usize = 6; +const INDEX_M24: usize = 7; +const INDEX_M31: usize = 8; +const INDEX_M32: usize = 9; +const INDEX_M33: usize = 10; +const INDEX_M34: usize = 11; +const INDEX_M41: usize = 12; +const INDEX_M42: usize = 13; +const INDEX_M43: usize = 14; +const INDEX_M44: usize = 15; + +#[op2] +impl DOMMatrixInner { + #[constructor] + #[cppgc] + pub fn constructor(#[buffer] buffer: &[f64], is_2d: bool) -> DOMMatrixInner { + DOMMatrixInner { + inner: RefCell::new(Matrix4::from_column_slice(buffer)), + is_2d: Cell::new(is_2d), + } + } + + #[reentrant] + #[static_method] + #[cppgc] + pub fn from_matrix( + #[webidl] init: DOMMatrixInit, + ) -> Result { + macro_rules! fixup { + ($value3d:expr, $value2d:expr, $default:expr) => {{ + if let Some(value3d) = $value3d { + if let Some(value2d) = $value2d { + if !(*value3d == *value2d || value3d.is_nan() && value2d.is_nan()) { + return Err(GeometryError::Inconsistent2DMatrix); + } + } + value3d + } else if let Some(value2d) = $value2d { + value2d + } else { + webidl::UnrestrictedDouble($default) + } + }}; + } + + let m11 = fixup!(init.m11, init.a, 1.0); + let m12 = fixup!(init.m12, init.b, 0.0); + let m21 = fixup!(init.m21, init.c, 0.0); + let m22 = fixup!(init.m22, init.d, 1.0); + let m41 = fixup!(init.m41, init.e, 0.0); + let m42 = fixup!(init.m42, init.f, 0.0); + let is_2d = { + let is_2d_can_be_true = *init.m13 == 0.0 + && *init.m14 == 0.0 + && *init.m23 == 0.0 + && *init.m24 == 0.0 + && *init.m31 == 0.0 + && *init.m32 == 0.0 + && *init.m33 == 1.0 + && *init.m34 == 0.0 + && *init.m43 == 0.0 + && *init.m44 == 1.0; + if let Some(is_2d) = init.is_2d { + if is_2d && !is_2d_can_be_true { + return Err(GeometryError::Inconsistent2DMatrix); + } else { + is_2d + } + } else { + is_2d_can_be_true + } + }; + + if is_2d { + Ok(DOMMatrixInner { + #[rustfmt::skip] + inner: RefCell::new(Matrix4::new( + *m11, *m21, 0.0, *m41, + *m12, *m22, 0.0, *m42, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + )), + is_2d: Cell::new(true), + }) + } else { + let DOMMatrixInit { + m13, + m14, + m23, + m24, + m31, + m32, + m33, + m34, + m43, + m44, + .. + } = init; + Ok(DOMMatrixInner { + #[rustfmt::skip] + inner: RefCell::new(Matrix4::new( + *m11, *m21, *m31, *m41, + *m12, *m22, *m32, *m42, + *m13, *m23, *m33, *m43, + *m14, *m24, *m34, *m44, + )), + is_2d: Cell::new(false), + }) + } + } + + #[static_method] + #[cppgc] + pub fn identity() -> DOMMatrixInner { + DOMMatrixInner { + inner: RefCell::new(Matrix4::identity()), + is_2d: Cell::new(true), + } + } + + #[cppgc] + pub fn clone(&self) -> DOMMatrixInner { + self.clone() + } + + #[fast] + #[getter] + pub fn a(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_A) } + } + + #[setter] + pub fn a(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_A) = *value; + } + } + + #[fast] + #[getter] + pub fn b(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_B) } + } + + #[setter] + pub fn b(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_B) = *value; + } + } + + #[fast] + #[getter] + pub fn c(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_C) } + } + + #[setter] + pub fn c(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_C) = *value; + } + } + + #[fast] + #[getter] + pub fn d(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_D) } + } + + #[setter] + pub fn d(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_D) = *value; + } + } + + #[fast] + #[getter] + pub fn e(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_E) } + } + + #[setter] + pub fn e(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_E) = *value; + } + } + + #[fast] + #[getter] + pub fn f(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_F) } + } + + #[setter] + pub fn f(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_F) = *value; + } + } + + #[fast] + #[getter] + pub fn m11(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M11) } + } + + #[setter] + pub fn m11(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M11) = *value; + } + } + + #[fast] + #[getter] + pub fn m12(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M12) } + } + + #[setter] + pub fn m12(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M12) = *value; + } + } + + #[fast] + #[getter] + pub fn m13(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M13) } + } + + #[setter] + pub fn m13(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M13) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m14(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M14) } + } + + #[setter] + pub fn m14(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M14) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m21(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M21) } + } + + #[setter] + pub fn m21(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M21) = *value; + } + } + + #[fast] + #[getter] + pub fn m22(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M22) } + } + + #[setter] + pub fn m22(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M22) = *value; + } + } + + #[fast] + #[getter] + pub fn m23(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M23) } + } + + #[setter] + pub fn m23(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M23) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m24(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M24) } + } + + #[setter] + pub fn m24(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M24) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m31(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M31) } + } + + #[setter] + pub fn m31(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M31) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m32(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M32) } + } + + #[setter] + pub fn m32(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M32) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m33(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M33) } + } + + #[setter] + pub fn m33(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M33) = *value; + } + if *value != 1.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m34(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M34) } + } + + #[setter] + pub fn m34(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M34) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m41(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M41) } + } + + #[setter] + pub fn m41(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M41) = *value; + } + } + + #[fast] + #[getter] + pub fn m42(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M42) } + } + + #[setter] + pub fn m42(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M42) = *value; + } + } + + #[fast] + #[getter] + pub fn m43(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M43) } + } + + #[setter] + pub fn m43(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M43) = *value; + } + if *value != 0.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn m44(&self) -> f64 { + // SAFETY: in-range access + unsafe { *self.inner.borrow().get_unchecked(INDEX_M44) } + } + + #[setter] + pub fn m44(&self, #[webidl] value: webidl::UnrestrictedDouble) { + // SAFETY: in-range access + unsafe { + *self.inner.borrow_mut().get_unchecked_mut(INDEX_M44) = *value; + } + if *value != 1.0 { + self.is_2d.set(false); + } + } + + #[fast] + #[getter] + pub fn is_2d(&self) -> bool { + self.is_2d.get() + } + + #[fast] + #[getter] + pub fn is_identity(&self) -> bool { + let inner = self.inner.borrow(); + // SAFETY: in-range access + unsafe { + *inner.get_unchecked(INDEX_M11) == 1.0 + && *inner.get_unchecked(INDEX_M12) == 0.0 + && *inner.get_unchecked(INDEX_M13) == 0.0 + && *inner.get_unchecked(INDEX_M14) == 0.0 + && *inner.get_unchecked(INDEX_M21) == 0.0 + && *inner.get_unchecked(INDEX_M22) == 1.0 + && *inner.get_unchecked(INDEX_M23) == 0.0 + && *inner.get_unchecked(INDEX_M24) == 0.0 + && *inner.get_unchecked(INDEX_M31) == 0.0 + && *inner.get_unchecked(INDEX_M32) == 0.0 + && *inner.get_unchecked(INDEX_M33) == 1.0 + && *inner.get_unchecked(INDEX_M34) == 0.0 + && *inner.get_unchecked(INDEX_M41) == 0.0 + && *inner.get_unchecked(INDEX_M42) == 0.0 + && *inner.get_unchecked(INDEX_M43) == 0.0 + && *inner.get_unchecked(INDEX_M44) == 1.0 + } + } + + #[fast] + #[getter] + pub fn is_finite(&self) -> bool { + self + .inner + .borrow() + .into_iter() + .all(|&item| item.is_finite()) + } + + #[arraybuffer] + pub fn to_buffer(&self) -> Vec { + // SAFETY: in-range access + unsafe { + slice::from_raw_parts( + self.inner.borrow().as_slice().as_ptr() as *mut u8, + mem::size_of::() * 16, + ) + } + .to_vec() + } + + #[cppgc] + pub fn translate( + &self, + #[webidl] tx: webidl::UnrestrictedDouble, + #[webidl] ty: webidl::UnrestrictedDouble, + #[webidl] tz: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_translate(&out, *tx, *ty, *tz); + out + } + + pub fn translate_self( + &self, + #[webidl] tx: webidl::UnrestrictedDouble, + #[webidl] ty: webidl::UnrestrictedDouble, + #[webidl] tz: webidl::UnrestrictedDouble, + ) { + matrix_translate(self, *tx, *ty, *tz); + } + + #[cppgc] + pub fn scale_without_origin( + &self, + #[webidl] sx: webidl::UnrestrictedDouble, + #[webidl] sy: webidl::UnrestrictedDouble, + #[webidl] sz: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_scale_without_origin(&out, *sx, *sy, *sz); + out + } + + pub fn scale_without_origin_self( + &self, + #[webidl] sx: webidl::UnrestrictedDouble, + #[webidl] sy: webidl::UnrestrictedDouble, + #[webidl] sz: webidl::UnrestrictedDouble, + ) { + matrix_scale_without_origin(self, *sx, *sy, *sz); + } + + #[cppgc] + pub fn scale_with_origin( + &self, + #[webidl] sx: webidl::UnrestrictedDouble, + #[webidl] sy: webidl::UnrestrictedDouble, + #[webidl] sz: webidl::UnrestrictedDouble, + #[webidl] origin_x: webidl::UnrestrictedDouble, + #[webidl] origin_y: webidl::UnrestrictedDouble, + #[webidl] origin_z: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_scale_with_origin( + &out, *sx, *sy, *sz, *origin_x, *origin_y, *origin_z, + ); + out + } + + pub fn scale_with_origin_self( + &self, + #[webidl] sx: webidl::UnrestrictedDouble, + #[webidl] sy: webidl::UnrestrictedDouble, + #[webidl] sz: webidl::UnrestrictedDouble, + #[webidl] origin_x: webidl::UnrestrictedDouble, + #[webidl] origin_y: webidl::UnrestrictedDouble, + #[webidl] origin_z: webidl::UnrestrictedDouble, + ) { + matrix_scale_with_origin( + self, *sx, *sy, *sz, *origin_x, *origin_y, *origin_z, + ); + } + + #[cppgc] + pub fn rotate( + &self, + #[webidl] roll_deg: webidl::UnrestrictedDouble, + #[webidl] pitch_deg: webidl::UnrestrictedDouble, + #[webidl] yaw_deg: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_rotate(&out, *roll_deg, *pitch_deg, *yaw_deg); + out + } + + pub fn rotate_self( + &self, + #[webidl] roll_deg: webidl::UnrestrictedDouble, + #[webidl] pitch_deg: webidl::UnrestrictedDouble, + #[webidl] yaw_deg: webidl::UnrestrictedDouble, + ) { + matrix_rotate(self, *roll_deg, *pitch_deg, *yaw_deg); + } + + #[cppgc] + pub fn rotate_from_vector( + &self, + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_rotate_from_vector(&out, *x, *y); + out + } + + pub fn rotate_from_vector_self( + &self, + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + ) { + matrix_rotate_from_vector(self, *x, *y); + } + + #[cppgc] + pub fn rotate_axis_angle( + &self, + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + #[webidl] z: webidl::UnrestrictedDouble, + #[webidl] angle_deg: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_rotate_axis_angle(&out, *x, *y, *z, *angle_deg); + out + } + + pub fn rotate_axis_angle_self( + &self, + #[webidl] x: webidl::UnrestrictedDouble, + #[webidl] y: webidl::UnrestrictedDouble, + #[webidl] z: webidl::UnrestrictedDouble, + #[webidl] angle_deg: webidl::UnrestrictedDouble, + ) { + matrix_rotate_axis_angle(self, *x, *y, *z, *angle_deg); + } + + #[cppgc] + pub fn skew_x( + &self, + #[webidl] x_deg: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_skew_x(&out, *x_deg); + out + } + + pub fn skew_x_self(&self, #[webidl] x_deg: webidl::UnrestrictedDouble) { + matrix_skew_x(self, *x_deg); + } + + #[cppgc] + pub fn skew_y( + &self, + #[webidl] y_deg: webidl::UnrestrictedDouble, + ) -> DOMMatrixInner { + let out = self.clone(); + matrix_skew_y(&out, *y_deg); + out + } + + pub fn skew_y_self(&self, #[webidl] y_deg: webidl::UnrestrictedDouble) { + matrix_skew_y(self, *y_deg); + } + + #[cppgc] + pub fn multiply(&self, #[cppgc] other: &DOMMatrixInner) -> DOMMatrixInner { + let out = DOMMatrixInner { + inner: RefCell::new(Matrix4::zeros()), + is_2d: Cell::new(true), + }; + matrix_multiply(&out, self, other); + out + } + + #[fast] + pub fn multiply_self(&self, #[cppgc] other: &DOMMatrixInner) { + let result = DOMMatrixInner { + inner: RefCell::new(Matrix4::zeros()), + is_2d: Cell::new(true), + }; + matrix_multiply(&result, self, other); + self.inner.borrow_mut().copy_from(&result.inner.borrow()); + self.is_2d.set(result.is_2d.get()); + } + + #[fast] + pub fn pre_multiply_self(&self, #[cppgc] other: &DOMMatrixInner) { + let result = DOMMatrixInner { + inner: RefCell::new(Matrix4::zeros()), + is_2d: Cell::new(true), + }; + matrix_multiply(&result, other, self); + self.inner.borrow_mut().copy_from(&result.inner.borrow()); + self.is_2d.set(result.is_2d.get()); + } + + #[cppgc] + pub fn flip_x(&self) -> DOMMatrixInner { + let out = self.clone(); + matrix_flip_x(&out); + out + } + + #[cppgc] + pub fn flip_y(&self) -> DOMMatrixInner { + let out = self.clone(); + matrix_flip_y(&out); + out + } + + #[cppgc] + pub fn inverse(&self) -> DOMMatrixInner { + let out = self.clone(); + matrix_inverse(&out); + out + } + + #[fast] + pub fn invert_self(&self) { + matrix_inverse(self); + } + + #[cppgc] + pub fn transform_point( + &self, + #[cppgc] point: &DOMPointInner, + ) -> DOMPointInner { + let out = DOMPointInner { + inner: RefCell::new(Vector4::zeros()), + }; + matrix_transform_point(self, point, &out); + out + } +} + +// TODO(petamoriken) Use f64::maximum instead https://github.com/rust-lang/rust/issues/91079 +#[inline] +fn maximum(a: f64, b: f64) -> f64 { + if a > b { + a + } else if b > a { + b + } else if a == b { + if a.is_sign_positive() && b.is_sign_negative() { + a + } else { + b + } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + a + b + } +} + +// TODO(petamoriken) Use f64::minimum instead https://github.com/rust-lang/rust/issues/91079 +#[inline] +fn minimum(a: f64, b: f64) -> f64 { + if a < b { + a + } else if b < a { + b + } else if a == b { + if a.is_sign_negative() && b.is_sign_positive() { + a + } else { + b + } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + a + b + } +} + +#[inline] +fn matrix_translate(matrix: &DOMMatrixInner, tx: f64, ty: f64, tz: f64) { + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + let shift = Vector3::new(tx, ty, tz); + inner.prepend_translation_mut(&shift); + matrix.is_2d.set(is_2d && tz == 0.0); +} + +#[inline] +fn matrix_scale_without_origin( + matrix: &DOMMatrixInner, + sx: f64, + sy: f64, + sz: f64, +) { + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + let scaling = Vector3::new(sx, sy, sz); + inner.prepend_nonuniform_scaling_mut(&scaling); + matrix.is_2d.set(is_2d && sz == 1.0); +} + +#[inline] +fn matrix_scale_with_origin( + matrix: &DOMMatrixInner, + sx: f64, + sy: f64, + sz: f64, + origin_x: f64, + origin_y: f64, + origin_z: f64, +) { + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + let scaling = Vector3::new(sx, sy, sz); + let mut shift = Vector3::new(origin_x, origin_y, origin_z); + inner.prepend_translation_mut(&shift); + inner.prepend_nonuniform_scaling_mut(&scaling); + shift.neg_mut(); + inner.prepend_translation_mut(&shift); + matrix.is_2d.set(is_2d && sz == 1.0 && origin_z == 0.0); +} + +#[inline] +fn matrix_rotate( + matrix: &DOMMatrixInner, + roll_deg: f64, + pitch_deg: f64, + yaw_deg: f64, +) { + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + let rotation = Rotation3::from_euler_angles( + roll_deg.to_radians(), + pitch_deg.to_radians(), + yaw_deg.to_radians(), + ) + .to_homogeneous(); + let mut result = Matrix4x3::zeros(); + inner.mul_to(&rotation.fixed_view::<4, 3>(0, 0), &mut result); + inner.set_column(0, &result.column(0)); + inner.set_column(1, &result.column(1)); + inner.set_column(2, &result.column(2)); + matrix + .is_2d + .set(is_2d && roll_deg == 0.0 && pitch_deg == 0.0); +} + +#[inline] +fn matrix_rotate_from_vector(matrix: &DOMMatrixInner, x: f64, y: f64) { + let mut inner = matrix.inner.borrow_mut(); + let rotation = + Rotation3::from_axis_angle(&Vector3::z_axis(), y.atan2(x)).to_homogeneous(); + let mut result = Matrix4x3::zeros(); + inner.mul_to(&rotation.fixed_view::<4, 3>(0, 0), &mut result); + inner.set_column(0, &result.column(0)); + inner.set_column(1, &result.column(1)); + inner.set_column(2, &result.column(2)); +} + +#[inline] +fn matrix_rotate_axis_angle( + matrix: &DOMMatrixInner, + x: f64, + y: f64, + z: f64, + angle_deg: f64, +) { + if x == 0.0 && y == 0.0 && z == 0.0 { + return; + } + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + let rotation = Rotation3::from_axis_angle( + &UnitVector3::new_normalize(Vector3::new(x, y, z)), + angle_deg.to_radians(), + ) + .to_homogeneous(); + let mut result = Matrix4x3::zeros(); + inner.mul_to(&rotation.fixed_view::<4, 3>(0, 0), &mut result); + inner.set_column(0, &result.column(0)); + inner.set_column(1, &result.column(1)); + inner.set_column(2, &result.column(2)); + matrix.is_2d.set(is_2d && x == 0.0 && y == 0.0); +} + +#[inline] +fn matrix_skew_x(matrix: &DOMMatrixInner, x_deg: f64) { + let mut inner = matrix.inner.borrow_mut(); + let skew = + Matrix4x2::new(1.0, x_deg.to_radians().tan(), 0.0, 1.0, 0.0, 0.0, 0.0, 0.0); + let mut result = Matrix4x2::zeros(); + inner.mul_to(&skew, &mut result); + inner.set_column(0, &result.column(0)); + inner.set_column(1, &result.column(1)); +} + +#[inline] +fn matrix_skew_y(matrix: &DOMMatrixInner, y_deg: f64) { + let mut inner = matrix.inner.borrow_mut(); + let skew = + Matrix4x2::new(1.0, 0.0, y_deg.to_radians().tan(), 1.0, 0.0, 0.0, 0.0, 0.0); + let mut result = Matrix4x2::zeros(); + inner.mul_to(&skew, &mut result); + inner.set_column(0, &result.column(0)); + inner.set_column(1, &result.column(1)); +} + +#[inline] +fn matrix_multiply( + out: &DOMMatrixInner, + lhs: &DOMMatrixInner, + rhs: &DOMMatrixInner, +) { + let lhs_inner = lhs.inner.borrow(); + let lhs_is_2d = lhs.is_2d.get(); + let rhs_inner = rhs.inner.borrow(); + let rhs_is_2d = rhs.is_2d.get(); + let mut out_inner = out.inner.borrow_mut(); + lhs_inner.mul_to(&rhs_inner, &mut out_inner); + out.is_2d.set(lhs_is_2d && rhs_is_2d); +} + +#[inline] +fn matrix_flip_x(matrix: &DOMMatrixInner) { + let mut inner = matrix.inner.borrow_mut(); + inner.column_mut(0).neg_mut(); +} + +#[inline] +fn matrix_flip_y(matrix: &DOMMatrixInner) { + let mut inner = matrix.inner.borrow_mut(); + inner.column_mut(1).neg_mut(); +} + +#[inline] +fn matrix_inverse(matrix: &DOMMatrixInner) { + let mut inner = matrix.inner.borrow_mut(); + let is_2d = matrix.is_2d.get(); + if inner.iter().any(|&x| x.is_infinite()) { + inner.fill(f64::NAN); + matrix.is_2d.set(false); + return; + } + if is_2d { + // SAFETY: in-range access + let mut matrix3 = unsafe { + Matrix3::new( + *inner.get_unchecked(INDEX_A), + *inner.get_unchecked(INDEX_C), + *inner.get_unchecked(INDEX_E), + *inner.get_unchecked(INDEX_B), + *inner.get_unchecked(INDEX_D), + *inner.get_unchecked(INDEX_F), + 0.0, + 0.0, + 1.0, + ) + }; + if !matrix3.try_inverse_mut() { + inner.fill(f64::NAN); + matrix.is_2d.set(false); + return; + } + // SAFETY: in-range access + unsafe { + *inner.get_unchecked_mut(INDEX_A) = *matrix3.get_unchecked(0); + *inner.get_unchecked_mut(INDEX_B) = *matrix3.get_unchecked(1); + *inner.get_unchecked_mut(INDEX_C) = *matrix3.get_unchecked(3); + *inner.get_unchecked_mut(INDEX_D) = *matrix3.get_unchecked(4); + *inner.get_unchecked_mut(INDEX_E) = *matrix3.get_unchecked(6); + *inner.get_unchecked_mut(INDEX_F) = *matrix3.get_unchecked(7); + } + } else if !inner.try_inverse_mut() { + inner.fill(f64::NAN); + } +} + +fn matrix_transform_point( + matrix: &DOMMatrixInner, + point: &DOMPointInner, + out: &DOMPointInner, +) { + let inner = matrix.inner.borrow(); + let point = point.inner.borrow(); + let mut result = out.inner.borrow_mut(); + inner.mul_to(&point, &mut result); +} diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index b3c3b299f03cbd..e7252cb0ece4d9 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -679,6 +679,9 @@ converters["UVString?"] = createNullableConverter( converters["sequence"] = createSequenceConverter( converters.double, ); +converters["sequence"] = createSequenceConverter( + converters["unrestricted double"], +); converters["sequence"] = createSequenceConverter( converters.object, ); diff --git a/ext/webidl/internal.d.ts b/ext/webidl/internal.d.ts index a884d982aabb2f..adfb6713563c80 100644 --- a/ext/webidl/internal.d.ts +++ b/ext/webidl/internal.d.ts @@ -348,6 +348,12 @@ declare module "ext:deno_webidl/00_webidl.js" { context?: string, opts?: any, ): number[]; + ["sequence"]( + v: any, + prefix?: string, + context?: string, + opts?: any, + ): number[]; [type: string]: ( v: any, diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index c2fbaca52f030f..87f7905efd99f2 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -55,6 +55,7 @@ deno_error.workspace = true deno_fetch.workspace = true deno_ffi.workspace = true deno_fs = { workspace = true, features = ["sync_fs"] } +deno_geometry.workspace = true deno_http.workspace = true deno_io.workspace = true deno_kv.workspace = true diff --git a/runtime/js/98_global_scope_window.js b/runtime/js/98_global_scope_window.js index c42a940a829796..2aee67d70cf069 100644 --- a/runtime/js/98_global_scope_window.js +++ b/runtime/js/98_global_scope_window.js @@ -7,18 +7,93 @@ import { op_bootstrap_user_agent, } from "ext:core/ops"; const { + ArrayPrototypeMap, + ArrayPrototypeSome, + Float64Array, + Number, + NumberIsNaN, ObjectDefineProperties, ObjectPrototypeIsPrototypeOf, + SafeRegExp, + StringPrototypeMatch, + StringPrototypeSplit, SymbolFor, + TypeError, } = primordials; import * as location from "ext:deno_web/12_location.js"; import * as console from "ext:deno_console/01_console.js"; import * as webidl from "ext:deno_webidl/00_webidl.js"; +import { DOMException } from "ext:deno_web/01_dom_exception.js"; import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js"; import * as webStorage from "ext:deno_webstorage/01_webstorage.js"; import * as prompt from "ext:runtime/41_prompt.js"; import { loadWebGPU } from "ext:deno_webgpu/00_init.js"; +import { createGeometryLoader } from "ext:deno_geometry/00_init.js"; + +const MATRIX_PATTERN = new SafeRegExp( + /^\s*matrix(3d)?\(([-\+0-9.e,\s]+)\)\s*$/iu, +); + +const loadGeometry = createGeometryLoader((transformList, prefix) => { + if (transformList === "") { + return { + // deno-fmt-ignore + matrix: new Float64Array([ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + ]), + is2D: true, + }; + } + + // Currently only parsing of a single matrix, matrix3d function without units + // as arguments is implemented + // TODO(petamoriken): Add CSS parser such as lightningcss to support more cases + const matrixMatch = StringPrototypeMatch(transformList, MATRIX_PATTERN); + if (matrixMatch !== null) { + const is2D = matrixMatch[1] === undefined; + /** @type {number[]} */ + const seq = ArrayPrototypeMap( + StringPrototypeSplit(matrixMatch[2], ","), + (str) => Number(str), + ); + if ( + is2D && seq.length !== 6 || + !is2D && seq.length !== 16 || + ArrayPrototypeSome(seq, (num) => NumberIsNaN(num)) + ) { + throw new DOMException( + `${prefix}: Failed to parse '${transformList}'`, + "SyntaxError", + ); + } + if (is2D) { + const { 0: a, 1: b, 2: c, 3: d, 4: e, 5: f } = seq; + return { + // deno-fmt-ignore + matrix: new Float64Array([ + a, b, 0, 0, + c, d, 0, 0, + 0, 0, 1, 0, + e, f, 0, 1, + ]), + is2D, + }; + } else { + return { + matrix: new Float64Array(seq), + is2D, + }; + } + } + + throw new TypeError( + `${prefix}: CSS parser is not fully implemented`, + ); +}, true); class Navigator { constructor() { @@ -121,6 +196,34 @@ const mainRuntimeGlobalProperties = { localStorage: core.propGetterOnly(webStorage.localStorage), sessionStorage: core.propGetterOnly(webStorage.sessionStorage), Storage: core.propNonEnumerable(webStorage.Storage), + DOMMatrix: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrix, + loadGeometry, + ), + DOMMatrixReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrixReadOnly, + loadGeometry, + ), + DOMPoint: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPoint, + loadGeometry, + ), + DOMPointReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPointReadOnly, + loadGeometry, + ), + DOMQuad: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMQuad, + loadGeometry, + ), + DOMRect: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRect, + loadGeometry, + ), + DOMRectReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRectReadOnly, + loadGeometry, + ), }; export { mainRuntimeGlobalProperties, memoizeLazy }; diff --git a/runtime/js/98_global_scope_worker.js b/runtime/js/98_global_scope_worker.js index f10bb2830dbbb6..d1fb739964363f 100644 --- a/runtime/js/98_global_scope_worker.js +++ b/runtime/js/98_global_scope_worker.js @@ -10,6 +10,7 @@ const { ObjectDefineProperties, ObjectPrototypeIsPrototypeOf, SymbolFor, + TypeError, } = primordials; import * as location from "ext:deno_web/12_location.js"; @@ -17,6 +18,13 @@ import * as console from "ext:deno_console/01_console.js"; import * as webidl from "ext:deno_webidl/00_webidl.js"; import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js"; import { loadWebGPU } from "ext:deno_webgpu/00_init.js"; +import { createGeometryLoader } from "ext:deno_geometry/00_init.js"; + +const loadGeometry = createGeometryLoader((_transformList, prefix) => { + throw new TypeError( + `${prefix}: Cannot parse CSS on Workers`, + ); +}, false); function memoizeLazy(f) { let v_ = null; @@ -115,6 +123,34 @@ const workerRuntimeGlobalProperties = { WorkerNavigator: core.propNonEnumerable(WorkerNavigator), navigator: core.propGetterOnly(() => workerNavigator), self: core.propGetterOnly(() => globalThis), + DOMMatrix: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrix, + loadGeometry, + ), + DOMMatrixReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMMatrixReadOnly, + loadGeometry, + ), + DOMPoint: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPoint, + loadGeometry, + ), + DOMPointReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMPointReadOnly, + loadGeometry, + ), + DOMQuad: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMQuad, + loadGeometry, + ), + DOMRect: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRect, + loadGeometry, + ), + DOMRectReadOnly: core.propNonEnumerableLazyLoaded( + (geometry) => geometry.DOMRectReadOnly, + loadGeometry, + ), }; export { workerRuntimeGlobalProperties }; diff --git a/runtime/lib.rs b/runtime/lib.rs index 92d6079f6d6bcb..eedda4fb9bdcd0 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -10,6 +10,7 @@ pub use deno_crypto; pub use deno_fetch; pub use deno_ffi; pub use deno_fs; +pub use deno_geometry; pub use deno_http; pub use deno_io; pub use deno_kv; diff --git a/runtime/shared.rs b/runtime/shared.rs index f712cef65be4d3..814ffacb5b7bd8 100644 --- a/runtime/shared.rs +++ b/runtime/shared.rs @@ -13,6 +13,7 @@ extension!(runtime, deno_web, deno_fetch, deno_cache, + deno_geometry, deno_websocket, deno_webstorage, deno_crypto, diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 80d90aab1ade75..3de6b589a7bde7 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -282,6 +282,7 @@ pub fn create_runtime_snapshot( deno_webgpu::deno_webgpu::init_ops_and_esm(), deno_canvas::deno_canvas::init_ops_and_esm(), deno_fetch::deno_fetch::init_ops_and_esm::(Default::default()), + deno_geometry::deno_geometry::init_ops_and_esm(), deno_cache::deno_cache::init_ops_and_esm::(None), deno_websocket::deno_websocket::init_ops_and_esm::( "".to_owned(), diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 7d6c890cfe9c4d..80cee2ccf28a7a 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -483,6 +483,7 @@ impl WebWorker { ..Default::default() }, ), + deno_geometry::deno_geometry::init_ops_and_esm(), deno_cache::deno_cache::init_ops_and_esm::( create_cache, ), diff --git a/runtime/worker.rs b/runtime/worker.rs index 3fa3e6828b2bc2..4c6074a6153e6a 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -380,6 +380,7 @@ impl MainWorker { ..Default::default() }, ), + deno_geometry::deno_geometry::init_ops_and_esm(), deno_cache::deno_cache::init_ops_and_esm::( create_cache, ), diff --git a/tests/integration/js_unit_tests.rs b/tests/integration/js_unit_tests.rs index 9ecec8b426c844..b241fb041b5d33 100644 --- a/tests/integration/js_unit_tests.rs +++ b/tests/integration/js_unit_tests.rs @@ -39,6 +39,7 @@ util::unit_test_factory!( filereader_test, files_test, fs_events_test, + geometry_test, get_random_values_test, globals_test, headers_test, diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 196184f3e08d91..d3944581807dc1 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -5762,7 +5762,6 @@ fn lsp_jsr_auto_import_completion() { json!({ "triggerKind": 1 }), ); assert!(!list.is_incomplete); - assert_eq!(list.items.len(), 268); let item = list.items.iter().find(|i| i.label == "add").unwrap(); assert_eq!(&item.label, "add"); assert_eq!( @@ -5842,7 +5841,6 @@ fn lsp_jsr_auto_import_completion_import_map() { json!({ "triggerKind": 1 }), ); assert!(!list.is_incomplete); - assert_eq!(list.items.len(), 268); let item = list.items.iter().find(|i| i.label == "add").unwrap(); assert_eq!(&item.label, "add"); assert_eq!(json!(&item.label_details), json!({ "description": "add" })); diff --git a/tests/unit/geometry_test.ts b/tests/unit/geometry_test.ts new file mode 100644 index 00000000000000..37ae864411dd77 --- /dev/null +++ b/tests/unit/geometry_test.ts @@ -0,0 +1,1195 @@ +// Copyright 2018-2025 the Deno authors. MIT license. +import { + assertAlmostEquals, + assertEquals, + assertStrictEquals, + assertThrows, +} from "./test_util.ts"; + +Deno.test(function matrixTransformPoint() { + const point = new DOMPoint(1, 2, 3, 4); + // deno-fmt-ignore + const matrix = DOMMatrix.fromMatrix({ + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }); + const point2 = point.matrixTransform(matrix); + const point3 = matrix.transformPoint(point); + assertEquals( + point, + new DOMPoint(1, 2, 3, 4), + ); + assertEquals( + point2, + new DOMPoint(30, 70, 110, 150), + ); + assertEquals( + point3, + new DOMPoint(30, 70, 110, 150), + ); +}); + +Deno.test(function matrixTranslate() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.translate(1, 2, 3); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2, m31: 3, m41: 1 * 1 + 2 * 2 + 3 * 3 + 4 * 1, + m12: 5, m22: 6, m32: 7, m42: 5 * 1 + 6 * 2 + 7 * 3 + 8 * 1, + m13: 9, m23: 10, m33: 11, m43: 9 * 1 + 10 * 2 + 11 * 3 + 12 * 1, + m14: 13, m24: 14, m34: 15, m44: 13 * 1 + 14 * 2 + 15 * 3 + 16 * 1, + }), + ); +}); + +Deno.test(function matrixTranslateSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.translateSelf(1, 2, 3); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2, m31: 3, m41: 1 * 1 + 2 * 2 + 3 * 3 + 4 * 1, + m12: 5, m22: 6, m32: 7, m42: 5 * 1 + 6 * 2 + 7 * 3 + 8 * 1, + m13: 9, m23: 10, m33: 11, m43: 9 * 1 + 10 * 2 + 11 * 3 + 12 * 1, + m14: 13, m24: 14, m34: 15, m44: 13 * 1 + 14 * 2 + 15 * 3 + 16 * 1, + }), + ); +}); + +Deno.test(function matrixScale() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale(1, 2, 3); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2 * 2, m31: 3 * 3, m41: 4, + m12: 5, m22: 6 * 2, m32: 7 * 3, m42: 8, + m13: 9, m23: 10 * 2, m33: 11 * 3, m43: 12, + m14: 13, m24: 14 * 2, m34: 15 * 3, m44: 16, + }), + ); +}); + +Deno.test(function matrixScaleSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scaleSelf(1, 2, 3); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2 * 2, m31: 3 * 3, m41: 4, + m12: 5, m22: 6 * 2, m32: 7 * 3, m42: 8, + m13: 9, m23: 10 * 2, m33: 11 * 3, m43: 12, + m14: 13, m24: 14 * 2, m34: 15 * 3, m44: 16, + }), + ); +}); + +Deno.test(function matrixScaleWithOrigin() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale(1, 2, 3, 4, 5, 6); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2 * 2, m31: 3 * 3, m41: -42, + m12: 5, m22: 6 * 2, m32: 7 * 3, m42: -106, + m13: 9, m23: 10 * 2, m33: 11 * 3, m43: -170, + m14: 13, m24: 14 * 2, m34: 15 * 3, m44: -234, + }), + ); +}); + +Deno.test(function matrixScaleWithOriginSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scaleSelf(1, 2, 3, 4, 5, 6); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2 * 2, m31: 3 * 3, m41: -42, + m12: 5, m22: 6 * 2, m32: 7 * 3, m42: -106, + m13: 9, m23: 10 * 2, m33: 11 * 3, m43: -170, + m14: 13, m24: 14 * 2, m34: 15 * 3, m44: -234, + }), + ); +}); + +Deno.test(function matrixScaleNonUniform() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scaleNonUniform(1, 2); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: 2 * 2, m31: 3, m41: 4, + m12: 5, m22: 6 * 2, m32: 7, m42: 8, + m13: 9, m23: 10 * 2, m33: 11, m43: 12, + m14: 13, m24: 14 * 2, m34: 15, m44: 16, + }), + ); +}); + +Deno.test(function matrixScale3d() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale3d(2); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 2, m21: 2 * 2, m31: 3 * 2, m41: 4, + m12: 5 * 2, m22: 6 * 2, m32: 7 * 2, m42: 8, + m13: 9 * 2, m23: 10 * 2, m33: 11 * 2, m43: 12, + m14: 13 * 2, m24: 14 * 2, m34: 15 * 2, m44: 16, + }), + ); +}); + +Deno.test(function matrixScale3dSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale3dSelf(2); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 2, m21: 2 * 2, m31: 3 * 2, m41: 4, + m12: 5 * 2, m22: 6 * 2, m32: 7 * 2, m42: 8, + m13: 9 * 2, m23: 10 * 2, m33: 11 * 2, m43: 12, + m14: 13 * 2, m24: 14 * 2, m34: 15 * 2, m44: 16, + }), + ); +}); + +Deno.test(function matrixScale3dWithOrigin() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale3d(2, 4, 5, 6); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 2, m21: 2 * 2, m31: 3 * 2, m41: -28, + m12: 5 * 2, m22: 6 * 2, m32: 7 * 2, m42: -84, + m13: 9 * 2, m23: 10 * 2, m33: 11 * 2, m43: -140, + m14: 13 * 2, m24: 14 * 2, m34: 15 * 2, m44: -196, + }), + ); +}); + +Deno.test(function matrixScale3dWithOriginSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.scale3dSelf(2, 4, 5, 6); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 2, m21: 2 * 2, m31: 3 * 2, m41: -28, + m12: 5 * 2, m22: 6 * 2, m32: 7 * 2, m42: -84, + m13: 9 * 2, m23: 10 * 2, m33: 11 * 2, m43: -140, + m14: 13 * 2, m24: 14 * 2, m34: 15 * 2, m44: -196, + }), + ); +}); + +Deno.test(function matrixRotate() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: -3, m21: -2, m31: -1, m41: 4, + m12: -7, m22: -6, m32: -5, m42: 8, + m13: -11, m23: -10, m33: -9, m43: 12, + m14: -15, m24: -14, m34: -13, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotate(0, 90, 180); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix2[key], + value, + ); + } +}); + +Deno.test(function matrixRotateSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: -3, m21: -2, m31: -1, m41: 4, + m12: -7, m22: -6, m32: -5, m42: 8, + m13: -11, m23: -10, m33: -9, m43: 12, + m14: -15, m24: -14, m34: -13, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotateSelf(0, 90, 180); + assertStrictEquals( + matrix, + matrix2, + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix[key], + value, + ); + } +}); + +Deno.test(function matrixRotateFromVector() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 2.121320343559643, m21: 0.7071067811865476, m31: 3, m41: 4, + m12: 7.778174593052023, m22: 0.7071067811865479, m32: 7, m42: 8, + m13: 13.435028842544405, m23: 0.7071067811865470, m33: 11, m43: 12, + m14: 19.091883092036785, m24: 0.7071067811865461, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotateFromVector(1, 1); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix2[key], + value, + ); + } +}); + +Deno.test(function matrixRotateFromVectorSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 2.121320343559643, m21: 0.7071067811865476, m31: 3, m41: 4, + m12: 7.778174593052023, m22: 0.7071067811865479, m32: 7, m42: 8, + m13: 13.435028842544405, m23: 0.7071067811865470, m33: 11, m43: 12, + m14: 19.091883092036785, m24: 0.7071067811865461, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotateFromVectorSelf(1, 1); + assertStrictEquals( + matrix, + matrix2, + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix[key], + value, + ); + } +}); + +Deno.test(function matrixRotateAxisAngle() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5.228294835332138, m22: 4.854398120227125, m32: 7.6876363080712045, m42: 8, + m13: 9.456589670664275, m23: 7.708796240454249, m33: 12.3752726161424090, m43: 12, + m14: 13.684884505996411, m24: 10.563194360681376, m34: 17.0629089242136120, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotateAxisAngle(1, 2, 3, 30); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix2[key], + value, + ); + } +}); + +Deno.test(function matrixRotateAxisAngleSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5.228294835332138, m22: 4.854398120227125, m32: 7.6876363080712045, m42: 8, + m13: 9.456589670664275, m23: 7.708796240454249, m33: 12.3752726161424090, m43: 12, + m14: 13.684884505996411, m24: 10.563194360681376, m34: 17.0629089242136120, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.rotateAxisAngleSelf(1, 2, 3, 30); + assertStrictEquals( + matrix, + matrix2, + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix[key], + value, + ); + } +}); + +Deno.test(function matrixSkewX() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 1, m21: 2.5773502691896257, m31: 3, m41: 4, + m12: 5, m22: 8.8867513459481270, m32: 7, m42: 8, + m13: 9, m23: 15.1961524227066300, m33: 11, m43: 12, + m14: 13, m24: 21.5055534994651330, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.skewX(30); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix2[key], + value, + ); + } +}); + +Deno.test(function matrixSkewXSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 1, m21: 2.5773502691896257, m31: 3, m41: 4, + m12: 5, m22: 8.8867513459481270, m32: 7, m42: 8, + m13: 9, m23: 15.1961524227066300, m33: 11, m43: 12, + m14: 13, m24: 21.5055534994651330, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.skewXSelf(30); + assertStrictEquals( + matrix, + matrix2, + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix[key], + value, + ); + } +}); + +Deno.test(function matrixSkewY() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 2.1547005383792515, m21: 2, m31: 3, m41: 4, + m12: 8.4641016151377530, m22: 6, m32: 7, m42: 8, + m13: 14.7735026918962560, m23: 10, m33: 11, m43: 12, + m14: 21.0829037686547600, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.skewY(30); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix2[key], + value, + ); + } +}); + +Deno.test(function matrixSkewYSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + // deno-fmt-ignore + const expect = { + m11: 2.1547005383792515, m21: 2, m31: 3, m41: 4, + m12: 8.4641016151377530, m22: 6, m32: 7, m42: 8, + m13: 14.7735026918962560, m23: 10, m33: 11, m43: 12, + m14: 21.0829037686547600, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.skewYSelf(30); + assertStrictEquals( + matrix, + matrix2, + ); + for ( + const [key, value] of Object.entries(expect) as [ + keyof typeof expect, + number, + ][] + ) { + assertAlmostEquals( + matrix[key], + value, + ); + } +}); + +Deno.test(function matrixMultiply() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.multiply({ m11: 1, m22: 2, m33: 3, m44: 4 }); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 1, m21: 2 * 2, m31: 3 * 3, m41: 4 * 4, + m12: 5 * 1, m22: 6 * 2, m32: 7 * 3, m42: 8 * 4, + m13: 9 * 1, m23: 10 * 2, m33: 11 * 3, m43: 12 * 4, + m14: 13 * 1, m24: 14 * 2, m34: 15 * 3, m44: 16 * 4, + }), + ); +}); + +Deno.test(function matrixMultiplySelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.multiplySelf({ m11: 1, m22: 2, m33: 3, m44: 4 }); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 1, m21: 2 * 2, m31: 3 * 3, m41: 4 * 4, + m12: 5 * 1, m22: 6 * 2, m32: 7 * 3, m42: 8 * 4, + m13: 9 * 1, m23: 10 * 2, m33: 11 * 3, m43: 12 * 4, + m14: 13 * 1, m24: 14 * 2, m34: 15 * 3, m44: 16 * 4, + }), + ); +}); + +Deno.test(function matrixMultiplySelfWithSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.multiplySelf(matrix); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 90, m21: 100, m31: 110, m41: 120, + m12: 202, m22: 228, m32: 254, m42: 280, + m13: 314, m23: 356, m33: 398, m43: 440, + m14: 426, m24: 484, m34: 542, m44: 600, + }), + ); +}); + +Deno.test(function matrixPreMultiplySelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.preMultiplySelf({ m11: 1, m22: 2, m33: 3, m44: 4 }); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1 * 1, m21: 2 * 1, m31: 3 * 1, m41: 4 * 1, + m12: 5 * 2, m22: 6 * 2, m32: 7 * 2, m42: 8 * 2, + m13: 9 * 3, m23: 10 * 3, m33: 11 * 3, m43: 12 * 3, + m14: 13 * 4, m24: 14 * 4, m34: 15 * 4, m44: 16 * 4, + }), + ); +}); + +Deno.test(function matrixPreMultiplySelfWithSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.preMultiplySelf(matrix); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 90, m21: 100, m31: 110, m41: 120, + m12: 202, m22: 228, m32: 254, m42: 280, + m13: 314, m23: 356, m33: 398, m43: 440, + m14: 426, m24: 484, m34: 542, m44: 600, + }), + ); +}); + +Deno.test(function matrixFlipX() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.flipX(); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: -1, m21: 2, m31: 3, m41: 4, + m12: -5, m22: 6, m32: 7, m42: 8, + m13: -9, m23: 10, m33: 11, m43: 12, + m14: -13, m24: 14, m34: 15, m44: 16, + }), + ); +}); + +Deno.test(function matrixFlipY() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 5, m22: 6, m32: 7, m42: 8, + m13: 9, m23: 10, m33: 11, m43: 12, + m14: 13, m24: 14, m34: 15, m44: 16, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.flipY(); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: -2, m31: 3, m41: 4, + m12: 5, m22: -6, m32: 7, m42: 8, + m13: 9, m23: -10, m33: 11, m43: 12, + m14: 13, m24: -14, m34: 15, m44: 16, + }), + ); +}); + +Deno.test(function matrixInverse() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 0, m22: 1, m32: 7, m42: 8, + m13: 0, m23: 0, m33: 1, m43: 12, + m14: 0, m24: 0, m34: 0, m44: 1, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.inverse(); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: -2, m31: 11, m41: -120, + m12: 0, m22: 1, m32: -7, m42: 76, + m13: 0, m23: 0, m33: 1, m43: -12, + m14: 0, m24: 0, m34: 0, m44: 1, + }), + ); +}); + +Deno.test(function matrixInvertSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 3, m41: 4, + m12: 0, m22: 1, m32: 7, m42: 8, + m13: 0, m23: 0, m33: 1, m43: 12, + m14: 0, m24: 0, m34: 0, m44: 1, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.invertSelf(); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: -2, m31: 11, m41: -120, + m12: 0, m22: 1, m32: -7, m42: 76, + m13: 0, m23: 0, m33: 1, m43: -12, + m14: 0, m24: 0, m34: 0, m44: 1, + }), + ); +}); + +Deno.test(function matrixInverse2D() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 0, m41: 4, + m12: 0, m22: 1, m32: 0, m42: 8, + m13: 0, m23: 0, m33: 1, m43: 0, + m14: 0, m24: 0, m34: 0, m44: 1, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.inverse(); + assertEquals( + matrix, + DOMMatrix.fromMatrix(init), + ); + assertEquals( + matrix2, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: -2, m31: 0, m41: 12, + m12: 0, m22: 1, m32: 0, m42: -8, + m13: 0, m23: 0, m33: 1, m43: 0, + m14: 0, m24: 0, m34: 0, m44: 1, + }), + ); +}); + +Deno.test(function matrixInvert2DSelf() { + // deno-fmt-ignore + const init = { + m11: 1, m21: 2, m31: 0, m41: 4, + m12: 0, m22: 1, m32: 0, m42: 8, + m13: 0, m23: 0, m33: 1, m43: 0, + m14: 0, m24: 0, m34: 0, m44: 1, + }; + const matrix = DOMMatrix.fromMatrix(init); + const matrix2 = matrix.invertSelf(); + assertStrictEquals( + matrix, + matrix2, + ); + assertEquals( + matrix, + // deno-fmt-ignore + DOMMatrix.fromMatrix({ + m11: 1, m21: -2, m31: 0, m41: 12, + m12: 0, m22: 1, m32: 0, m42: -8, + m13: 0, m23: 0, m33: 1, m43: 0, + m14: 0, m24: 0, m34: 0, m44: 1, + }), + ); +}); + +Deno.test(function prototypeOverwrite() { + const point = new DOMPointReadOnly(); + Object.setPrototypeOf(point, DOMPoint.prototype); + assertThrows( + () => { + // @ts-ignore test + point.x = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + point.y = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + point.z = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + point.w = 1; + }, + TypeError, + "Illegal invocation", + ); + + const rect = new DOMRectReadOnly(); + Object.setPrototypeOf(rect, DOMRect.prototype); + assertThrows( + () => { + // @ts-ignore test + rect.x = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + rect.y = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + rect.width = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + rect.height = 1; + }, + TypeError, + "Illegal invocation", + ); + + const matrix = new DOMMatrixReadOnly(); + Object.setPrototypeOf(matrix, DOMMatrix.prototype); + assertThrows( + () => { + // @ts-ignore test + matrix.a = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.b = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.c = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.d = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.e = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.f = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m11 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m12 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m13 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m14 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m21 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m22 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m23 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m24 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m31 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m32 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m33 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m34 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m41 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m42 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m43 = 1; + }, + TypeError, + "Illegal invocation", + ); + assertThrows( + () => { + // @ts-ignore test + matrix.m44 = 1; + }, + TypeError, + "Illegal invocation", + ); +}); diff --git a/tests/unit/test_util.ts b/tests/unit/test_util.ts index 6e7865ea7a43d4..c4fa660b986e69 100644 --- a/tests/unit/test_util.ts +++ b/tests/unit/test_util.ts @@ -6,6 +6,7 @@ export { colors }; import { join, resolve } from "@std/path"; export { assert, + assertAlmostEquals, assertEquals, assertFalse, AssertionError, diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 6d2cc38562fef2..fe39ee5a36b3b0 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -14246,5 +14246,210 @@ "eventsource-constructor-url-bogus.any.sharedworker.html": false, "request-credentials.window.html": false, "request-redirect.window.html": false + }, + "css": { + "geometry": { + "DOMMatrix-001.html": [ + "new DOMMatrix(\"none\")", + "new DOMMatrix(\" none\")", + "new DOMMatrix(\"none \")", + "new DOMMatrix(\"NONE\")", + "new DOMMatrix(\"none/**/\")", + "new DOMMatrix(\"/**/none\")", + "new DOMMatrix(\"scale(2) translateX(5px) translateY(5px)\")", + "new DOMMatrix(\"scale(2, 2) translateX(5px) translateY(5px)\")", + "new DOMMatrix(\"scale(2)translateX(5px)translateY(5px)\")", + "new DOMMatrix(\"scale(2) translateX(calc(2 * 2.5px)) translateY(5px)\")", + "new DOMMatrix(\"scale(2) translateX(5px) translateY(5px) rotate(5deg) rotate(-5deg)\")", + "new DOMMatrix(\"translateX (5px)\")", + "new DOMMatrix(\"scale(2 2) translateX(5) translateY(5)\")", + "new DOMMatrix(\"scale(2, 2), translateX(5) ,translateY(5)\")", + "new DOMMatrix(\"translateX(5em)\")", + "new DOMMatrix(\"translateX(5ex)\")", + "new DOMMatrix(\"translateX(5ch)\")", + "new DOMMatrix(\"translateX(5rem)\")", + "new DOMMatrix(\"translateX(5cqw)\")", + "new DOMMatrix(\"translateX(5cqh)\")", + "new DOMMatrix(\"translateX(5cqb)\")", + "new DOMMatrix(\"translateX(5cqi)\")", + "new DOMMatrix(\"translateX(5cqmin)\")", + "new DOMMatrix(\"translateX(5cqmax)\")", + "new DOMMatrix(\"translateX(5vw)\")", + "new DOMMatrix(\"translateX(5vh)\")", + "new DOMMatrix(\"translateX(5vb)\")", + "new DOMMatrix(\"translateX(5vi)\")", + "new DOMMatrix(\"translateX(5vmin)\")", + "new DOMMatrix(\"translateX(5vmax)\")", + "new DOMMatrix(\"translateX(5%)\")", + "new DOMMatrix(\"rotate(5)\")", + "new DOMMatrix(\"rotate(5, 5, 5)\")", + "new DOMMatrix(\"rotate(5, 5px, 5px)\")", + "new DOMMatrix(\"rotate(5deg, 5px, 5px)\")", + "new DOMMatrix(\" \")", + "new DOMMatrix(\"/**/\")", + "new DOMMatrix(\"\\0\")", + "new DOMMatrix(\";\")", + "new DOMMatrix(\"none;\")", + "new DOMMatrix(\"null\")", + "new DOMMatrix(null)", + "new DOMMatrix(\"undefined\")", + "new DOMMatrix(\"inherit\")", + "new DOMMatrix(\"initial\")", + "new DOMMatrix(\"unset\")", + "new DOMMatrix(\"scale(2, 2), translateX(5px) translateY(5px)\")", + "new DOMMatrixReadOnly(\"none\")", + "new DOMMatrixReadOnly(\" none\")", + "new DOMMatrixReadOnly(\"none \")", + "new DOMMatrixReadOnly(\"NONE\")", + "new DOMMatrixReadOnly(\"none/**/\")", + "new DOMMatrixReadOnly(\"/**/none\")", + "new DOMMatrixReadOnly(\"scale(2) translateX(5px) translateY(5px)\")", + "new DOMMatrixReadOnly(\"scale(2, 2) translateX(5px) translateY(5px)\")", + "new DOMMatrixReadOnly(\"scale(2)translateX(5px)translateY(5px)\")", + "new DOMMatrixReadOnly(\"scale(2) translateX(calc(2 * 2.5px)) translateY(5px)\")", + "new DOMMatrixReadOnly(\"scale(2) translateX(5px) translateY(5px) rotate(5deg) rotate(-5deg)\")", + "new DOMMatrixReadOnly(\"translateX (5px)\")", + "new DOMMatrixReadOnly(\"scale(2 2) translateX(5) translateY(5)\")", + "new DOMMatrixReadOnly(\"scale(2, 2), translateX(5) ,translateY(5)\")", + "new DOMMatrixReadOnly(\"translateX(5em)\")", + "new DOMMatrixReadOnly(\"translateX(5ex)\")", + "new DOMMatrixReadOnly(\"translateX(5ch)\")", + "new DOMMatrixReadOnly(\"translateX(5rem)\")", + "new DOMMatrixReadOnly(\"translateX(5cqw)\")", + "new DOMMatrixReadOnly(\"translateX(5cqh)\")", + "new DOMMatrixReadOnly(\"translateX(5cqb)\")", + "new DOMMatrixReadOnly(\"translateX(5cqi)\")", + "new DOMMatrixReadOnly(\"translateX(5cqmin)\")", + "new DOMMatrixReadOnly(\"translateX(5cqmax)\")", + "new DOMMatrixReadOnly(\"translateX(5vw)\")", + "new DOMMatrixReadOnly(\"translateX(5vh)\")", + "new DOMMatrixReadOnly(\"translateX(5vb)\")", + "new DOMMatrixReadOnly(\"translateX(5vi)\")", + "new DOMMatrixReadOnly(\"translateX(5vmin)\")", + "new DOMMatrixReadOnly(\"translateX(5vmax)\")", + "new DOMMatrixReadOnly(\"translateX(5%)\")", + "new DOMMatrixReadOnly(\"rotate(5)\")", + "new DOMMatrixReadOnly(\"rotate(5, 5, 5)\")", + "new DOMMatrixReadOnly(\"rotate(5, 5px, 5px)\")", + "new DOMMatrixReadOnly(\"rotate(5deg, 5px, 5px)\")", + "new DOMMatrixReadOnly(\" \")", + "new DOMMatrixReadOnly(\"/**/\")", + "new DOMMatrixReadOnly(\"\\0\")", + "new DOMMatrixReadOnly(\";\")", + "new DOMMatrixReadOnly(\"none;\")", + "new DOMMatrixReadOnly(\"null\")", + "new DOMMatrixReadOnly(null)", + "new DOMMatrixReadOnly(\"undefined\")", + "new DOMMatrixReadOnly(\"inherit\")", + "new DOMMatrixReadOnly(\"initial\")", + "new DOMMatrixReadOnly(\"unset\")", + "new DOMMatrixReadOnly(\"scale(2, 2), translateX(5px) translateY(5px)\")" + ], + "DOMMatrix-002.html": true, + "DOMMatrix-003.html": true, + "DOMMatrix-a-f-alias.html": true, + "DOMMatrix-attributes.html": true, + "DOMMatrix-css-string.worker.html": true, + "DOMMatrix-invert-invertible.html": true, + "DOMMatrix-invert-non-invertible.html": true, + "DOMMatrix-invert-preserves-2d.html": true, + "DOMMatrix-newobject.html": true, + "DOMMatrix-stringifier.html": [ + "WebKitCSSMatrix stringifier: identity (2d)", + "WebKitCSSMatrix stringifier: identity (3d)", + "WebKitCSSMatrix stringifier: NaN (2d)", + "WebKitCSSMatrix stringifier: NaN (3d)", + "WebKitCSSMatrix stringifier: Infinity (2d)", + "WebKitCSSMatrix stringifier: Infinity (3d)", + "WebKitCSSMatrix stringifier: -Infinity (2d)", + "WebKitCSSMatrix stringifier: -Infinity (3d)", + "WebKitCSSMatrix stringifier: 1/3 (2d)", + "WebKitCSSMatrix stringifier: 1/3 (3d)", + "WebKitCSSMatrix stringifier: 1/300000 (2d)", + "WebKitCSSMatrix stringifier: 1/300000 (3d)", + "WebKitCSSMatrix stringifier: 1/300000000 (2d)", + "WebKitCSSMatrix stringifier: 1/300000000 (3d)", + "WebKitCSSMatrix stringifier: 100000 + (1/3) (2d)", + "WebKitCSSMatrix stringifier: 100000 + (1/3) (3d)", + "WebKitCSSMatrix stringifier: Math.pow(2, 53) + 1 (2d)", + "WebKitCSSMatrix stringifier: Math.pow(2, 53) + 1 (3d)", + "WebKitCSSMatrix stringifier: Math.pow(2, 53) + 2 (2d)", + "WebKitCSSMatrix stringifier: Math.pow(2, 53) + 2 (3d)", + "WebKitCSSMatrix stringifier: Number.MAX_VALUE (2d)", + "WebKitCSSMatrix stringifier: Number.MAX_VALUE (3d)", + "WebKitCSSMatrix stringifier: Number.MIN_VALUE (2d)", + "WebKitCSSMatrix stringifier: Number.MIN_VALUE (3d)", + "WebKitCSSMatrix stringifier: throwing getters (2d)", + "WebKitCSSMatrix stringifier: throwing getters (3d)" + ], + "DOMMatrix2DInit-validate-fixup.html": false, + "DOMMatrixInit-validate-fixup.html": true, + "DOMPoint-001.html": true, + "DOMPoint-002.html": true, + "DOMQuad-001.html": true, + "DOMQuad-002.html": true, + "DOMQuad-nan.html": true, + "DOMRect-001.html": true, + "DOMRect-002.html": true, + "DOMRect-nan.html": true, + "DOMRectList.html": false, + "WebKitCSSMatrix.html": false, + "WebKitCSSMatrix.worker.html": true, + "historical.html": true, + "idlharness.any.html": [ + "DOMPointReadOnly interface: existence and properties of interface object", + "DOMPoint interface: existence and properties of interface object", + "DOMRectReadOnly interface: existence and properties of interface object", + "DOMRect interface: existence and properties of interface object", + "DOMRectList interface: existence and properties of interface object", + "DOMRectList interface object length", + "DOMRectList interface object name", + "DOMRectList interface: existence and properties of interface prototype object", + "DOMRectList interface: existence and properties of interface prototype object's \"constructor\" property", + "DOMRectList interface: existence and properties of interface prototype object's @@unscopables property", + "DOMRectList interface: attribute length", + "DOMRectList interface: operation item(unsigned long)", + "DOMQuad interface: existence and properties of interface object", + "DOMMatrixReadOnly interface: existence and properties of interface object", + "DOMMatrix interface: existence and properties of interface object" + ], + "idlharness.any.worker.html": [ + "DOMPointReadOnly interface: existence and properties of interface object", + "DOMPoint interface: existence and properties of interface object", + "DOMRectReadOnly interface: existence and properties of interface object", + "DOMRect interface: existence and properties of interface object", + "DOMQuad interface: existence and properties of interface object", + "DOMMatrixReadOnly interface: existence and properties of interface object", + "DOMMatrix interface: existence and properties of interface object" + ], + "spec-examples.html": true, + "structured-serialization.html": [ + "DOMPointReadOnly clone: basic", + "DOMPointReadOnly clone: custom property", + "DOMPointReadOnly clone: non-initial values", + "DOMPoint clone: basic", + "DOMPoint clone: custom property", + "DOMPoint clone: non-initial values", + "DOMRectReadOnly clone: basic", + "DOMRectReadOnly clone: custom property", + "DOMRectReadOnly clone: non-initial values", + "DOMRect clone: basic", + "DOMRect clone: custom property", + "DOMRect clone: non-initial values", + "DOMQuad clone: basic", + "DOMQuad clone: custom property", + "DOMQuad clone: non-initial values", + "DOMMatrixReadOnly clone: basic", + "DOMMatrixReadOnly clone: custom property", + "DOMMatrixReadOnly clone: non-initial values (2d)", + "DOMMatrixReadOnly clone: non-initial values (3d)", + "DOMMatrix clone: basic", + "DOMMatrix clone: custom property", + "DOMMatrix clone: non-initial values (2d)", + "DOMMatrix clone: non-initial values (3d)", + "DOMRectList clone" + ], + "DOMMatrix-invertSelf.html": true + } } } diff --git a/tools/core_import_map.json b/tools/core_import_map.json index 935c7179a136e2..b83b6c7ea1d40b 100644 --- a/tools/core_import_map.json +++ b/tools/core_import_map.json @@ -17,6 +17,8 @@ "ext:deno_fetch/26_fetch.js": "../ext/fetch/26_fetch.js", "ext:deno_ffi/00_ffi.js": "../ext/ffi/00_ffi.js", "ext:deno_fs/30_fs.js": "../ext/fs/30_fs.js", + "ext:deno_geometry/00_init.js": "../ext/geometry/00_init.js", + "ext:deno_geometry/01_geometry.js": "../ext/geometry/01_geometry.js", "ext:deno_http/00_serve.ts": "../ext/http/00_serve.ts", "ext:deno_http/01_http.js": "../ext/http/01_http.js", "ext:deno_io/12_io.js": "../ext/io/12_io.js", diff --git a/tools/jsdoc_checker.js b/tools/jsdoc_checker.js index 034782136c13e7..ecac03c8948134 100755 --- a/tools/jsdoc_checker.js +++ b/tools/jsdoc_checker.js @@ -13,6 +13,7 @@ const libs = [ join(ROOT_PATH, "ext/webstorage/lib.deno_webstorage.d.ts"), join(ROOT_PATH, "ext/canvas/lib.deno_canvas.d.ts"), join(ROOT_PATH, "ext/crypto/lib.deno_crypto.d.ts"), + join(ROOT_PATH, "ext/geometry/lib.deno_geometry.d.ts"), join(ROOT_PATH, "ext/net/lib.deno_net.d.ts"), join(ROOT_PATH, "cli/tsc/dts/lib.deno.ns.d.ts"), join(ROOT_PATH, "cli/tsc/dts/lib.deno.shared_globals.d.ts"),