diff --git a/Configurations/Version.xcconfig b/Configurations/Version.xcconfig
index 21cb2ace1206..cfcca3a32eb6 100644
--- a/Configurations/Version.xcconfig
+++ b/Configurations/Version.xcconfig
@@ -35,6 +35,7 @@ SHORT_VERSION_STRING = $(SHORT_VERSION_STRING_$(CONFIGURATION))
SYSTEM_VERSION_MAJOR_SHORT_MACOS = $(SYSTEM_VERSION_MAJOR_SHORT_MACOS_$(TARGET_MAC_OS_X_VERSION_MAJOR))
SYSTEM_VERSION_MAJOR_SHORT_MACOS_150000 = 15
SYSTEM_VERSION_MAJOR_SHORT_MACOS_160000 = 16
+SYSTEM_VERSION_MAJOR_SHORT_MACOS_260000 = 26
SYSTEM_VERSION_MAJOR_SHORT_MACOS_270000 = 27
SYSTEM_VERSION_MAJOR_SHORT_MACOS_280000 = 28
SYSTEM_VERSION_MAJOR_SHORT_MACOS_290000 = 29
@@ -44,6 +45,7 @@ SYSTEM_VERSION_MAJOR_SHORT_MACOS_300000 = 30
SYSTEM_VERSION_PREFIX = $(SYSTEM_VERSION_PREFIX_$(PLATFORM_NAME)_$(SYSTEM_VERSION_MAJOR_SHORT_MACOS))
SYSTEM_VERSION_PREFIX_macosx_15 = 20
SYSTEM_VERSION_PREFIX_macosx_16 = 21
+SYSTEM_VERSION_PREFIX_macosx_26 = 21
SYSTEM_VERSION_PREFIX_macosx_27 = 22
SYSTEM_VERSION_PREFIX_macosx_28 = 23
SYSTEM_VERSION_PREFIX_macosx_29 = 24
diff --git a/JSTests/microbenchmarks/get-by-val-array-storage-sparse-hole.js b/JSTests/microbenchmarks/get-by-val-array-storage-sparse-hole.js
new file mode 100644
index 000000000000..ef68d4097357
--- /dev/null
+++ b/JSTests/microbenchmarks/get-by-val-array-storage-sparse-hole.js
@@ -0,0 +1,32 @@
+//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+// Hole/miss-dominated reads of a large sparse array (ArrayStorage mode with a sparse map). Every read
+// hits an in-bounds hole that is absent from the sparse map, so the int-indexed GetByVal slow path
+// (operationGetByValArrayStorageInt) must resolve it to undefined via the (sane) prototype chain.
+function get(array, i)
+{
+ return array[i];
+}
+noInline(get);
+
+var maxIndex = 200000;
+var step = 16;
+
+var array = [];
+for (var i = maxIndex - step; i >= 0; i -= step)
+ array[i] = i + 1;
+
+var expectedPass = 0;
+for (var i = 1; i < maxIndex; i += step) // i = 1, 17, 33, ... are all holes (never written).
+ ++expectedPass;
+
+var iterations = 400;
+var holes = 0;
+for (var iter = 0; iter < iterations; ++iter) {
+ for (var i = 1; i < maxIndex; i += step) {
+ if (get(array, i) === void 0)
+ ++holes;
+ }
+}
+
+if (holes !== expectedPass * iterations)
+ throw "Error: bad hole count: " + holes;
diff --git a/JSTests/microbenchmarks/get-by-val-array-storage-sparse.js b/JSTests/microbenchmarks/get-by-val-array-storage-sparse.js
new file mode 100644
index 000000000000..2cd433b339d0
--- /dev/null
+++ b/JSTests/microbenchmarks/get-by-val-array-storage-sparse.js
@@ -0,0 +1,31 @@
+//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+// Hit-dominated reads of a large sparse array (ArrayStorage mode with a sparse map). Every read
+// resolves through the int-indexed GetByVal slow path (operationGetByValArrayStorageInt) and finds
+// its value in the sparse map.
+function get(array, i)
+{
+ return array[i];
+}
+noInline(get);
+
+var maxIndex = 200000;
+var step = 16; // 1/16 density (< 1/8) keeps the array in ArrayStorage with a sparse map.
+
+var array = [];
+// Descending writes: the first one is far beyond length, forcing ArrayStorage + sparse map.
+for (var i = maxIndex - step; i >= 0; i -= step)
+ array[i] = i + 1;
+
+var expectedPass = 0;
+for (var i = 0; i < maxIndex; i += step)
+ expectedPass += i + 1;
+
+var iterations = 800;
+var sum = 0;
+for (var iter = 0; iter < iterations; ++iter) {
+ for (var i = 0; i < maxIndex; i += step)
+ sum += get(array, i);
+}
+
+if (sum !== expectedPass * iterations)
+ throw "Error: bad sum: " + sum;
diff --git a/JSTests/stress/arguments-elimination-multiple-inline-call-frames.js b/JSTests/stress/arguments-elimination-multiple-inline-call-frames.js
new file mode 100644
index 000000000000..8a87b89cc5cd
--- /dev/null
+++ b/JSTests/stress/arguments-elimination-multiple-inline-call-frames.js
@@ -0,0 +1,38 @@
+//@ skip if $buildType == "debug"
+//@ runDefault("--useConcurrentJIT=false", "--jitPolicyScale=0", "--maximumFunctionForCallInlineCandidateBytecodeCostForFTL=500")
+
+let g = 0;
+function restY(c, ...r) { g = c ? 1 : 2; return r; }
+function h(c, ...r) { return r; }
+function h2(...r) { return r; }
+function sink() {
+ let out = [];
+ for (let i = 0; i < arguments.length; i++) out.push(arguments[i]);
+ return out;
+}
+noInline(sink);
+
+function restX(c, ...rx) {
+ let arr = [...rx, ...restY(c, ...rx)];
+ let dummy = [0, 0, 0, 0, 0, 0, 0, h(50, 9.9, 8.8)];
+ return [sink.apply(null, arr), dummy];
+}
+for (let i = 0; i < 1000000; i++) restX(i & 1, 0.1, 0.2);
+
+function makeSrc(k) {
+return `
+(function() {
+function victim${k}(c1) {
+ let q = restX(c1, 0.1, 0.2);
+ let z = h2(7.7, 6.6);
+ return [q, z];
+}
+noInline(victim${k});
+for (let i = 0; i < 1000000; i++) {
+ victim${k}(i & 1);
+}
+})()
+`;
+}
+
+for (let k = 0; k < 30; k++) eval(makeSrc(k));
diff --git a/JSTests/stress/array-indexof-ensure-still-alive.js b/JSTests/stress/array-indexof-ensure-still-alive.js
new file mode 100644
index 000000000000..3ede4c9daf16
--- /dev/null
+++ b/JSTests/stress/array-indexof-ensure-still-alive.js
@@ -0,0 +1,15 @@
+//@ runDefault("--useFTLJIT=1", "--jitPolicyScale=0.1", "--useConcurrentJIT=0", "--useConcurrentGC=0", "--sweepSynchronously=1", "--collectContinuously=1")
+
+function opt(s, needle) {
+ return [s + "A", s + "B", s + "C", s + "D", s + "E", s + "F", s + "G", s + "H"].indexOf(needle);
+}
+noInline(opt);
+
+let big = "Q".repeat(1024 * 1024);
+let needleStr = "Z".repeat(big.length + 1);
+
+for (let i = 0; i < 2000; i++)
+ opt(big, (i & 1) ? needleStr : 1234);
+
+for (let i = 0; i < 10000; i++)
+ opt(big, needleStr);
diff --git a/JSTests/stress/dfg-ensure-absence-cached-dictionary-then.js b/JSTests/stress/dfg-ensure-absence-cached-dictionary-then.js
new file mode 100644
index 000000000000..5edeb5ee04f8
--- /dev/null
+++ b/JSTests/stress/dfg-ensure-absence-cached-dictionary-then.js
@@ -0,0 +1,87 @@
+function createObject1() {
+ const tmp = {
+ toJSON: 1,
+ a: 1,
+ };
+
+ Object.create(tmp);
+
+ return tmp;
+}
+
+function createObject2() {
+ const tmp = {
+ b: 1,
+ toJSON: {}
+ };
+
+ Object.create(tmp);
+
+ return tmp;
+}
+
+function opt(container1, object2, array, thenable, flags) {
+ const promise = new Promise(() => {});
+
+ container1.x;
+ thenable.x;
+
+ const object1 = Object.getPrototypeOf(container1);
+
+ let tmp = object1;
+ object1.a;
+
+ if (flags & 1) {
+ tmp = object2;
+ tmp.b;
+
+ 0[0];
+ }
+
+ +tmp.toJSON;
+ +tmp.toJSON;
+
+ array[0];
+ Promise.resolve(+tmp.toJSON === 1 ? thenable : promise);
+
+ array[0] = 2.3023e-320;
+}
+
+function main() {
+ noDFG(main);
+
+ const object1 = createObject1();
+ const object2 = createObject2();
+
+ createObject1().z = 1;
+
+ const container1 = Object.create(object1);
+
+ const thenable = {
+ x: 1
+ };
+
+ for (let i = 0; i < 100; i++) {
+ thenable['a' + i] = 1;
+ }
+
+ const array = {
+ 0: 1.1
+ };
+
+ JSON.stringify(container1);
+
+ for (let i = 0; i < 200; i++) {
+ opt(container1, object2, array, thenable, i);
+ }
+
+ thenable.__defineGetter__('then', () => {
+ array[0] = {};
+ });
+
+ opt(container1, object2, array, thenable, 0);
+
+ array[0].x;
+}
+
+main();
diff --git a/JSTests/stress/multi-put-by-offset-reallocating-storage-needs-write-barrier.js b/JSTests/stress/multi-put-by-offset-reallocating-storage-needs-write-barrier.js
new file mode 100644
index 000000000000..3539c166af87
--- /dev/null
+++ b/JSTests/stress/multi-put-by-offset-reallocating-storage-needs-write-barrier.js
@@ -0,0 +1,32 @@
+//@ runDefault("--useConcurrentJIT=false", "--jitPolicyScale=0.1", "--useConcurrentGC=false", "--verifyGC=true", "--gcMaxHeapSize=500000")
+
+var g_value = {};
+
+function makeObj() { return {}; }
+
+function foo(cond) {
+ let a = makeObj();
+ a.p1 = 1;
+ a.p2 = 1;
+ a.p3 = 1;
+ a.p4 = 1;
+ a.p5 = 1;
+ if (cond)
+ a.y = 1;
+ else
+ a.z = 1;
+ a.x = g_value;
+ return a;
+}
+noInline(foo);
+
+for (let i = 0; i < testLoopCount; ++i) {
+ g_value = {};
+ foo(i & 1);
+}
+
+var holder = new Array(100000).fill(null);
+fullGC();
+
+for (let i = 0; i < testLoopCount * 10; ++i)
+ holder[i % 100000] = foo(i & 1);
diff --git a/JSTests/stress/regexp-many-non-greedy-paren-groups.js b/JSTests/stress/regexp-many-non-greedy-paren-groups.js
new file mode 100644
index 000000000000..bedfd82896b5
--- /dev/null
+++ b/JSTests/stress/regexp-many-non-greedy-paren-groups.js
@@ -0,0 +1,25 @@
+// Test that regular expressions with many sequential non-greedy quantified
+// parenthesized groups produce correct results at various sizes.
+
+function testLargeNonGreedyParens(n) {
+ let s = '(?:a){0,2}?'.repeat(n);
+
+ let r = new RegExp(s);
+
+ let result = 'aaa'.match(r);
+ if (result === null)
+ throw new Error("Expected match for n=" + n);
+ if (result.index !== 0)
+ throw new Error("Expected index 0 for n=" + n + ", got " + result.index);
+
+ let replaced = 'a'.replace(r, 'x');
+ if (typeof replaced !== 'string')
+ throw new Error("replace failed for n=" + n);
+}
+
+testLargeNonGreedyParens(10);
+testLargeNonGreedyParens(100);
+testLargeNonGreedyParens(1000);
+testLargeNonGreedyParens(2000);
+testLargeNonGreedyParens(4000);
+testLargeNonGreedyParens(8193);
diff --git a/JSTests/stress/regress-174630697.js b/JSTests/stress/regress-174630697.js
new file mode 100644
index 000000000000..5b422c5fafdd
--- /dev/null
+++ b/JSTests/stress/regress-174630697.js
@@ -0,0 +1,25 @@
+const icCount = 100;
+const structCount = 16;
+
+let body = "var x = 0;\n";
+for (let i = 0; i < icCount; i++)
+ body += "x += o.p;\n";
+body += "return x;\n";
+
+let objs = [];
+for (let i = 0; i < structCount; i++) {
+ let o = {};
+ o["k" + i] = i;
+ o.p = 1;
+ objs.push(o);
+}
+
+let f = new Function("o", body);
+
+for (let j = 0; j < 130; j++)
+ f(objs[j % structCount]);
+
+for (let j = 0; j < 100000; j++)
+ f(objs[j % structCount]);
+
+f(42);
diff --git a/JSTests/stress/slowputarraystorage-stale-structure-bit.js b/JSTests/stress/slowputarraystorage-stale-structure-bit.js
new file mode 100644
index 000000000000..0fe63895e357
--- /dev/null
+++ b/JSTests/stress/slowputarraystorage-stale-structure-bit.js
@@ -0,0 +1,34 @@
+Object.defineProperty(Object.prototype, 0, { get() {}, configurable: true });
+delete Object.prototype[0];
+let target = [1, 2, 3];
+Object.defineProperty(target, "length", { writable: false });
+
+let proxyGet = new Proxy(target, {
+ get: (t, k) => k === "length" ? 999 : t[k]
+});
+
+try {
+ let lengthLie = proxyGet.length;
+ if (lengthLie === 999) {
+ throw "\"get\" trap successfully returned a lying value (999) for a non-configurable, non-writable property!";
+ }
+} catch (e) {
+ if (!(e instanceof TypeError)) {
+ throw "Expected TypeError for \"get\" trap invariant violation, got: " + e;
+ }
+}
+
+let proxySet = new Proxy(target, {
+ set: (t, k, v) => true
+});
+
+try {
+ let setSuccess = Reflect.set(proxySet, "length", 999);
+ if (setSuccess === true && target.length !== 999) {
+ throw "Reflect.set returned true claiming success on a non-configurable, non-writable property!";
+ }
+} catch (e) {
+ if (!(e instanceof TypeError)) {
+ throw "Expected TypeError for \"set\" trap invariant violation, got: " + e;
+ }
+}
diff --git a/JSTests/stress/spread-with-OnlyAtomStringsStructure.js b/JSTests/stress/spread-with-OnlyAtomStringsStructure.js
new file mode 100644
index 000000000000..da8a25a94426
--- /dev/null
+++ b/JSTests/stress/spread-with-OnlyAtomStringsStructure.js
@@ -0,0 +1,6 @@
+//@ runDefault("--forceEagerCompilation=1", "--validateAbstractInterpreterState=1")
+
+const array = [""];
+
+for (let index = 0; index < testLoopCount; index++)
+ (() => {})(...array);
diff --git a/JSTests/stress/typedarray-from-oob.js b/JSTests/stress/typedarray-from-oob.js
new file mode 100644
index 000000000000..eba79c459c51
--- /dev/null
+++ b/JSTests/stress/typedarray-from-oob.js
@@ -0,0 +1,47 @@
+function testResize(ctor, bytesPerElement, initialBytes, shrinkBytes, resizeAt) {
+ const newCount = shrinkBytes / bytesPerElement;
+ const resizableArrayBuffer = new ArrayBuffer(initialBytes, { maxByteLength: initialBytes * 4 });
+ const source = new ctor(resizableArrayBuffer);
+ source[Symbol.iterator] = null;
+
+ let callbacks = 0;
+ ctor.from(source, (val, index) => {
+ if (index === resizeAt)
+ resizableArrayBuffer.resize(shrinkBytes);
+ callbacks++;
+ return val;
+ });
+
+ const expected = Math.max(resizeAt + 1, newCount);
+ if (callbacks > expected)
+ throw new Error(ctor.name + ": " + callbacks + " callbacks (expected <= " + expected + ")");
+}
+
+function testDetach(detachAt) {
+ const arrayBuffer = new ArrayBuffer(256);
+ const source = new Int32Array(arrayBuffer);
+ source[Symbol.iterator] = null;
+
+ let callbacks = 0;
+ try {
+ Int32Array.from(source, (val, index) => {
+ if (index === detachAt)
+ arrayBuffer.transfer();
+ callbacks++;
+ return val;
+ });
+ } catch (e) {
+ return;
+ }
+
+ if (callbacks > detachAt + 1)
+ throw new Error("detach: " + callbacks + " callbacks (expected <= " + (detachAt + 1) + ")");
+}
+
+testResize(Int32Array, 4, 4096, 16, 4);
+testResize(Int32Array, 4, 4096, 8, 8);
+testResize(Float64Array, 8, 8192, 32, 8);
+testResize(Uint8Array, 1, 1024, 4, 8);
+testResize(Int32Array, 4, 4096, 8, 0);
+testDetach(4);
+testDetach(0);
diff --git a/JSTests/stress/yarr-negative-offset.js b/JSTests/stress/yarr-negative-offset.js
new file mode 100644
index 000000000000..c9a51ec18814
--- /dev/null
+++ b/JSTests/stress/yarr-negative-offset.js
@@ -0,0 +1,33 @@
+//@ skip if $memoryLimited
+
+// YarrJIT OOB crash — page-aligned variant
+//
+// sizeof(StringImpl) = 0x14, page_size = 0x4000 (Apple Silicon 16K pages)
+// Solve: 0x14 + (K + 0x40000000)*2 ≡ 0 (mod 0x4000) → K = 0x1FF6
+//
+// Pattern: \u0100{K} [\u0100] \u0100{0x3FFFFFFF} flags: y
+// Subject: "\u0100".repeat(K + 0x40000000)
+//
+// The OOB ldrh lands at alloc_base + page_size*N exactly → unmapped → SIGSEGV
+
+"use strict";
+
+const K = 0x1FF6;
+const LEN = K + 0x40000000; // 0x40001FF6
+const QUANT = 0x3FFFFFFF;
+
+// allocate
+let s;
+try {
+ s = "\u0100".repeat(LEN);
+} catch (e) {
+ print("[!] OOM: " + e);
+ quit();
+}
+if(s.length !== 0x40001ff6) throw new Error("unexpected s.length "+s.length);
+
+let pattern = "\\u0100{" + K + "}[\\u0100]\\u0100{" + QUANT + "}";
+let re = new RegExp(pattern, "y");
+re.lastIndex = 0;
+
+re.test(s); // should SIGSEGV if the bug is present
diff --git a/JSTests/wasm/gc/private-fields-and-methods.js b/JSTests/wasm/gc/private-fields-and-methods.js
new file mode 100644
index 000000000000..89c37c87e30f
--- /dev/null
+++ b/JSTests/wasm/gc/private-fields-and-methods.js
@@ -0,0 +1,170 @@
+import * as assert from "../assert.js";
+import { instantiate } from "./wast-wrapper.js";
+
+function testPrivateMethodOnStruct() {
+ let m = instantiate(`
+ (module
+ (type (struct (field i32)))
+ (func (export "make") (result anyref)
+ (struct.new 0 (i32.const 42)))
+ (func (export "use") (param (ref 0)) (result i32)
+ (struct.get 0 0 (local.get 0)))
+ )
+ `);
+ const s = m.exports.make();
+
+ class B { constructor() { return s; } }
+ class D extends B {
+ #m() {}
+ constructor() { super(); }
+ }
+
+ assert.throws(
+ () => new D(),
+ TypeError,
+ "Cannot add private method to a WebAssembly GC object"
+ );
+
+ // Struct must remain usable after the rejected attempt.
+ assert.eq(m.exports.use(s), 42);
+}
+
+function testPrivateFieldOnStruct() {
+ let m = instantiate(`
+ (module
+ (type (struct (field i32)))
+ (func (export "make") (result anyref)
+ (struct.new 0 (i32.const 42)))
+ (func (export "use") (param (ref 0)) (result i32)
+ (struct.get 0 0 (local.get 0)))
+ )
+ `);
+ const s = m.exports.make();
+
+ class B { constructor() { return s; } }
+ class D extends B {
+ #x = 1;
+ constructor() { super(); }
+ }
+
+ assert.throws(
+ () => new D(),
+ TypeError,
+ "Cannot define private field on a WebAssembly GC object"
+ );
+
+ assert.eq(m.exports.use(s), 42);
+}
+
+function testPrivateMethodOnArray() {
+ let m = instantiate(`
+ (module
+ (type (array i32))
+ (func (export "make") (result anyref)
+ (array.new 0 (i32.const 7) (i32.const 3)))
+ (func (export "use") (param (ref 0) i32) (result i32)
+ (array.get 0 (local.get 0) (local.get 1)))
+ )
+ `);
+ const a = m.exports.make();
+
+ class B { constructor() { return a; } }
+ class D extends B {
+ #m() {}
+ constructor() { super(); }
+ }
+
+ assert.throws(
+ () => new D(),
+ TypeError,
+ "Cannot add private method to a WebAssembly GC object"
+ );
+
+ assert.eq(m.exports.use(a, 0), 7);
+}
+
+function testPrivateFieldOnArray() {
+ let m = instantiate(`
+ (module
+ (type (array i32))
+ (func (export "make") (result anyref)
+ (array.new 0 (i32.const 7) (i32.const 3)))
+ (func (export "use") (param (ref 0) i32) (result i32)
+ (array.get 0 (local.get 0) (local.get 1)))
+ )
+ `);
+ const a = m.exports.make();
+
+ class B { constructor() { return a; } }
+ class D extends B {
+ #x = 1;
+ constructor() { super(); }
+ }
+
+ assert.throws(
+ () => new D(),
+ TypeError,
+ "Cannot define private field on a WebAssembly GC object"
+ );
+
+ assert.eq(m.exports.use(a, 0), 7);
+}
+
+function testPrivateGetterOnStruct() {
+ let m = instantiate(`
+ (module
+ (type (struct (field i32)))
+ (func (export "make") (result anyref)
+ (struct.new 0 (i32.const 42)))
+ (func (export "use") (param (ref 0)) (result i32)
+ (struct.get 0 0 (local.get 0)))
+ )
+ `);
+ const s = m.exports.make();
+
+ class B { constructor() { return s; } }
+ class D extends B {
+ get #x() { return 1; }
+ constructor() { super(); }
+ }
+
+ assert.throws(
+ () => new D(),
+ TypeError,
+ "Cannot add private method to a WebAssembly GC object"
+ );
+
+ assert.eq(m.exports.use(s), 42);
+}
+
+function testGCSurvival() {
+ let m = instantiate(`
+ (module
+ (type (struct (field i32)))
+ (func (export "make") (result anyref)
+ (struct.new 0 (i32.const 42)))
+ (func (export "use") (param (ref 0)) (result i32)
+ (struct.get 0 0 (local.get 0)))
+ )
+ `);
+ const s = m.exports.make();
+
+ class B { constructor() { return s; } }
+ class D extends B {
+ #m() {}
+ constructor() { super(); }
+ }
+
+ try { new D(); } catch {}
+
+ // The struct must survive GC with its structure intact.
+ gc();
+ assert.eq(m.exports.use(s), 42);
+}
+
+testPrivateMethodOnStruct();
+testPrivateFieldOnStruct();
+testPrivateMethodOnArray();
+testPrivateFieldOnArray();
+testPrivateGetterOnStruct();
+testGCSurvival();
diff --git a/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter-expected.html b/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter-expected.html
new file mode 100644
index 000000000000..c6e7d04568b5
--- /dev/null
+++ b/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter-expected.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ PASS
+
+
+
diff --git a/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter.html b/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter.html
new file mode 100644
index 000000000000..6136535bf7c1
--- /dev/null
+++ b/LayoutTests/fast/css/highlight-pseudo-fill-applies-color-filter.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ PASS
+
+
+
diff --git a/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash-expected.txt b/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash-expected.txt
new file mode 100644
index 000000000000..49004868ff5d
--- /dev/null
+++ b/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash-expected.txt
@@ -0,0 +1,3 @@
+This test passes if it does not crash.
+
+
diff --git a/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash.xhtml b/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash.xhtml
new file mode 100644
index 000000000000..fd96782b0ae3
--- /dev/null
+++ b/LayoutTests/fast/custom-elements/xml-parser-reparent-during-construction-crash.xhtml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+This test passes if it does not crash.
+
+
+
diff --git a/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash-expected.txt b/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash-expected.txt
new file mode 100644
index 000000000000..730ebf66a0da
--- /dev/null
+++ b/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash.
diff --git a/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash.html b/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash.html
new file mode 100644
index 000000000000..a800754e8aa4
--- /dev/null
+++ b/LayoutTests/fast/mediasession/metadata/artwork-image-loader-callback-crash.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+This test passes if it doesn't crash.
+
+
\ No newline at end of file
diff --git a/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto-expected.txt b/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto-expected.txt
new file mode 100644
index 000000000000..ce0583968657
--- /dev/null
+++ b/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto-expected.txt
@@ -0,0 +1,3 @@
+
+PASS applyConstraints while takePhoto is happening on a cloned track
+
diff --git a/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto.html b/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto.html
new file mode 100644
index 000000000000..15bb77cc7738
--- /dev/null
+++ b/LayoutTests/fast/mediastream/applyConstraints-with-takePhoto.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash-expected.txt b/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash-expected.txt
new file mode 100644
index 000000000000..03831620f648
--- /dev/null
+++ b/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash-expected.txt
@@ -0,0 +1 @@
+Test passes if it does not crash.
diff --git a/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash.html b/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash.html
new file mode 100644
index 000000000000..26498a31beeb
--- /dev/null
+++ b/LayoutTests/fast/webcodecs/audio-data-close-during-gc-crash.html
@@ -0,0 +1,64 @@
+
+
+
+
diff --git a/LayoutTests/fast/webgpu/nocrash/fuzz-176882934-expected.txt b/LayoutTests/fast/webgpu/nocrash/fuzz-176882934-expected.txt
new file mode 100644
index 000000000000..0533f45490c1
--- /dev/null
+++ b/LayoutTests/fast/webgpu/nocrash/fuzz-176882934-expected.txt
@@ -0,0 +1,2 @@
+Pass
+
diff --git a/LayoutTests/fast/webgpu/nocrash/fuzz-176882934.html b/LayoutTests/fast/webgpu/nocrash/fuzz-176882934.html
new file mode 100644
index 000000000000..a1c824b04dfe
--- /dev/null
+++ b/LayoutTests/fast/webgpu/nocrash/fuzz-176882934.html
@@ -0,0 +1,60 @@
+
+
+
diff --git a/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass-expected.txt b/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass-expected.txt
new file mode 100644
index 000000000000..9490d44ca416
--- /dev/null
+++ b/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass-expected.txt
@@ -0,0 +1 @@
+PASS: validation error raised for undersized buffer in render pass after compute cache priming CONTROL: PASS: validation error raised for fresh BindGroup with undersized buffer
diff --git a/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass.html b/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass.html
new file mode 100644
index 000000000000..0fba47cb94d6
--- /dev/null
+++ b/LayoutTests/fast/webgpu/pipeline-id-collision-bindgroup-validation-bypass.html
@@ -0,0 +1,120 @@
+
+
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_176812014-expected.txt b/LayoutTests/fast/webgpu/regression/repro_176812014-expected.txt
new file mode 100644
index 000000000000..ee4a6c18face
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_176812014-expected.txt
@@ -0,0 +1,2 @@
+PASS dispatch was rejected: Auto-generated layouts mismatch
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_176812014.html b/LayoutTests/fast/webgpu/regression/repro_176812014.html
new file mode 100644
index 000000000000..238837725c97
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_176812014.html
@@ -0,0 +1,73 @@
+
+
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-expected.txt
new file mode 100644
index 000000000000..b32cb0600d27
--- /dev/null
+++ b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: The Content Security Policy directive 'frame-ancestors' is ignored when delivered via an HTML meta element.
+CONSOLE MESSAGE: The Content Security Policy directive 'report-uri' is ignored when delivered via an HTML meta element.
+CONSOLE MESSAGE: Unrecognized Content-Security-Policy directive 'aaa'.
+
+This tests that mixed-case Content Security Policy directive names are lowercased, so the console warnings refer to them in lowercase.
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic-expected.txt
new file mode 100644
index 000000000000..d7523311b6a4
--- /dev/null
+++ b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic-expected.txt
@@ -0,0 +1,4 @@
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/security/contentSecurityPolicy/resources/simpleSourcedScript.js because it does not appear in the script-src directive of the Content Security Policy.
+
+PASS An uppercase SCRIPT-SRC directive still applies strict-dynamic, so a parser-inserted script is blocked.
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic.html b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic.html
new file mode 100644
index 000000000000..4d2e72118528
--- /dev/null
+++ b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive-strict-dynamic.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive.html b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive.html
new file mode 100644
index 000000000000..c1cdbea3f05c
--- /dev/null
+++ b/LayoutTests/http/tests/security/contentSecurityPolicy/directive-name-case-insensitive.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+This tests that mixed-case Content Security Policy directive names are lowercased, so the console warnings refer to them in lowercase.
+
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate-expected.txt
new file mode 100644
index 000000000000..38eed2435aec
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate-expected.txt
@@ -0,0 +1,10 @@
+Tests that rejecting requestStorageAccess() without a user gesture does not synthesize user activation.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Rejection handler correctly had no user activation.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate.html b/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate.html
new file mode 100644
index 000000000000..5b9aea0c27da
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-rejected-without-gesture-should-not-activate.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/http/tests/storageAccess/resources/request-storage-access-without-gesture-check-activation-iframe.html b/LayoutTests/http/tests/storageAccess/resources/request-storage-access-without-gesture-check-activation-iframe.html
new file mode 100644
index 000000000000..5610afddfdf8
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/resources/request-storage-access-without-gesture-check-activation-iframe.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading-expected.txt b/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading-expected.txt
new file mode 100644
index 000000000000..fc07a2561091
--- /dev/null
+++ b/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading-expected.txt
@@ -0,0 +1,4 @@
+
+
+PASS pushState() in parent while child is doing initial navigation, then go back
+
diff --git a/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading.html b/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading.html
new file mode 100644
index 000000000000..769278f25057
--- /dev/null
+++ b/LayoutTests/http/wpt/site-isolation/history-traversal/history-traversal-navigate-parent-while-child-loading.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change-expected.txt b/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change-expected.txt
new file mode 100644
index 000000000000..3d61793dea0e
--- /dev/null
+++ b/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change-expected.txt
@@ -0,0 +1,3 @@
+
+PASS AudioEncoder handles switching PCM sample format from f32-planar to s16 mid-stream
+
diff --git a/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change.html b/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change.html
new file mode 100644
index 000000000000..5544ce2eccf0
--- /dev/null
+++ b/LayoutTests/http/wpt/webcodecs/audio-encoder-pcm-format-change.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/at-function-cssom-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/at-function-cssom-expected.txt
index 111ae2e696d4..0861559d1851 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/at-function-cssom-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/at-function-cssom-expected.txt
@@ -13,24 +13,24 @@ PASS item()
PASS Indexed property getter
PASS @supports in body
PASS CSSFunctionRule.name
-FAIL CSSFunctionRule.getParameters() assert_object_equals: property "type" expected "" got "*"
-FAIL CSSFunctionRule.returnType assert_equals: expected "" but got "*"
+PASS CSSFunctionRule.getParameters()
+PASS CSSFunctionRule.returnType
PASS CSSFunctionRule escapes
PASS CSSFunctionRule.cssText (--empty)
-FAIL CSSFunctionRule.cssText (--ret-length) assert_equals: expected "@function --ret-length() returns { }" but got "@function --ret-length() { }"
-FAIL CSSFunctionRule.cssText (--ret-length-auto) assert_equals: expected "@function --ret-length-auto() returns type( | auto) { }" but got "@function --ret-length-auto() { }"
+PASS CSSFunctionRule.cssText (--ret-length)
+PASS CSSFunctionRule.cssText (--ret-length-auto)
PASS CSSFunctionRule.cssText (--param-single)
-FAIL CSSFunctionRule.cssText (--param-typed) assert_equals: expected "@function --param-typed(--x ) { }" but got "@function --param-typed(--x) { }"
-FAIL CSSFunctionRule.cssText (--param-typed-default) assert_equals: expected "@function --param-typed-default(--x : 10px) { }" but got "@function --param-typed-default(--x: 10px) { }"
+PASS CSSFunctionRule.cssText (--param-typed)
+PASS CSSFunctionRule.cssText (--param-typed-default)
PASS CSSFunctionRule.cssText (--param-default)
PASS CSSFunctionRule.cssText (--param-multi)
-FAIL CSSFunctionRule.cssText (--param-multi-mixed) assert_equals: expected "@function --param-multi-mixed(--x: 10px, --y, --z ) { }" but got "@function --param-multi-mixed(--x: 10px, --y, --z) { }"
+PASS CSSFunctionRule.cssText (--param-multi-mixed)
PASS CSSFunctionRule.cssText (--body-result)
PASS CSSFunctionRule.cssText (--body-locals)
-FAIL CSSFunctionRule.cssText (--param-type-fn) assert_equals: expected "@function --param-type-fn(--x ) { }" but got "@function --param-type-fn(--x) { }"
+PASS CSSFunctionRule.cssText (--param-type-fn)
PASS CSSFunctionRule.cssText (--param-type-fn-uni)
PASS CSSFunctionRule.cssText (--ret-type-fn)
PASS CSSFunctionRule.cssText (--ret-type-fn-uni)
PASS CSSFunctionRule.cssText (--body-result-multi)
-FAIL CSSFunctionRule.cssText (--escaped-) assert_equals: expected "@function --escaped-\\9 -tab(--param-\\9 -tab) { --local-\\9 -tab: 1px; }" but got "@function --escaped-\\9 -tab(--param-\\9 -tab) { --local-\t-tab: 1px; }"
+PASS CSSFunctionRule.cssText (--escaped-)
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles-expected.txt
index 6add1050a037..46035d2c174e 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles-expected.txt
@@ -20,8 +20,8 @@ PASS Cycle through global, self
PASS Cycle through local, other function
PASS Cycle through local, other function, fallback in function
PASS Cycle through various variables and other functions
-FAIL Function in a cycle with its own default assert_equals: expected "PASS" but got "10px"
-FAIL Cyclic defaults assert_equals: expected "42px PASS-y PASS-z" but got "42px var(--z) var(--y)"
-FAIL Cyclic outer --b shadows custom property assert_equals: expected "PASS" but got "var(--b)"
+PASS Function in a cycle with its own default
+PASS Cyclic defaults
+PASS Cyclic outer --b shadows custom property
PASS Locals are function specific
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-eval-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-eval-expected.txt
index 2cefce64fa61..fed4beebcf02 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-eval-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-eval-expected.txt
@@ -19,19 +19,19 @@ PASS Parameter with complex type (px)
PASS Passing argument to inner function
PASS var() in argument resolved before call
PASS var() in argument resolved before call, typed
-FAIL Argument captures IACVT due to invalid var() assert_equals: expected "PASS" but got ""
-FAIL Argument captures IACVT due to invalid var(), typed assert_equals: expected "PASS" but got ""
+PASS Argument captures IACVT due to invalid var()
+PASS Argument captures IACVT due to invalid var(), typed
PASS Argument captures IACVT due to type mismatch
PASS Single parameter with default value
PASS Multiple parameters with defaults
PASS Multiple parameters with defaults, typed
-FAIL Default referencing another parameter assert_equals: expected "5px 5px" but got "5px var(--x)"
-FAIL Default referencing another parameter, local interference assert_equals: expected "17px 5px" but got "17px var(--x)"
-FAIL Default referencing another defaulted parameter assert_equals: expected "5px 5px" but got "5px var(--x)"
+PASS Default referencing another parameter
+PASS Default referencing another parameter, local interference
+PASS Default referencing another defaulted parameter
FAIL Typed default with reference assert_equals: expected "5px 6px" but got ""
-FAIL IACVT arguments are defaulted assert_equals: expected "1 2 3" but got ""
-FAIL IACVT arguments are defaulted, typed assert_equals: expected "1 2 3" but got ""
-FAIL Arguments are defaulted on type mismatch assert_equals: expected "1 2 3" but got ""
+PASS IACVT arguments are defaulted
+PASS IACVT arguments are defaulted, typed
+PASS Arguments are defaulted on type mismatch
PASS Unused local
PASS Local does not affect outer scope
PASS Substituting local in result
@@ -55,9 +55,9 @@ PASS Inner function call should see resolved outer locals
PASS Inner function call should see resolved outer locals (reverse)
PASS Parameter shadows custom property
PASS Local shadows parameter
-FAIL IACVT argument shadows outer scope assert_equals: expected "PASS" but got ""
-FAIL IACVT argument shadows outer scope, typed assert_equals: expected "PASS" but got ""
-FAIL IACVT argument shadows outer scope, type mismatch assert_equals: expected "PASS" but got "FAIL"
+PASS IACVT argument shadows outer scope
+PASS IACVT argument shadows outer scope, typed
+PASS IACVT argument shadows outer scope, type mismatch
PASS Missing only argument
PASS Missing one argument of several
FAIL Passing list as only argument assert_equals: expected "1px,2px" but got "{1px,2px}"
@@ -68,7 +68,7 @@ FAIL Passing {} as argument assert_equals: expected "{}" but got "{{}}"
FAIL Passing non-whole-value {} as argument assert_equals: expected "foo{}" but got "{foo{}}"
PASS Local variable with initial keyword
PASS Local variable with initial keyword, defaulted
-FAIL Local variable with initial keyword, no value via IACVT-capture assert_equals: expected "PASS" but got ""
+PASS Local variable with initial keyword, no value via IACVT-capture
PASS Default with initial keyword
FAIL initial appearing via fallback assert_equals: expected "PASS" but got ""
PASS Local variable with inherit keyword
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-attr-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-attr-expected.txt
index 5d1141889307..b03177520afe 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-attr-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-attr-expected.txt
@@ -7,7 +7,7 @@ PASS Return attr(type()) from untyped function
PASS Return attr(type()) from typed function
PASS Return attr(type(*)) from typed function
PASS Return attr(type(*)) from untyped function
-FAIL attr() in default parameter value assert_equals: expected "42px" but got "784px"
+PASS attr() in default parameter value
PASS attr() in local variable
PASS Returned url() is attr-tainted
PASS Returned url() is attr-tainted, typed attr()
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-expected.html
new file mode 100644
index 000000000000..f2d20af47c8b
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-expected.html
@@ -0,0 +1,18 @@
+
+
+CSS Pseudo-Elements Reference: highlight text fill color uses 'color', not 'stroke-color'
+
+
+
+Test passes if the word below is green.
+PASS
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-ref.html
new file mode 100644
index 000000000000..f2d20af47c8b
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color-ref.html
@@ -0,0 +1,18 @@
+
+
+
CSS Pseudo-Elements Reference: highlight text fill color uses 'color', not 'stroke-color'
+
+
+
+Test passes if the word below is green.
+PASS
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color.html
new file mode 100644
index 000000000000..59367b367307
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/highlight-fill-color-ignores-stroke-color.html
@@ -0,0 +1,24 @@
+
+
+
CSS Pseudo-Elements Test: highlight text fill color uses 'color', not 'stroke-color'
+
+
+
+
+
+
+
+Test passes if the word below is green.
+PASS
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/cssom/variable-names-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/cssom/variable-names-expected.txt
index 205fff67ec8f..05ae5a07ca87 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/cssom/variable-names-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/cssom/variable-names-expected.txt
@@ -1,8 +1,8 @@
PASS custom property '--a'
-FAIL custom property '--a;b' assert_equals: appears on specified style (after serialization/re-parsing) expected 1 but got 0
+PASS custom property '--a;b'
PASS custom property '---'
-FAIL custom property '--\' assert_equals: appears on specified style (after serialization/re-parsing) expected 1 but got 0
+PASS custom property '--\'
PASS custom property '--ab'
PASS custom property '--0'
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/animations/animateMotion-spline-invalid-keyTimes-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/svg/animations/animateMotion-spline-invalid-keyTimes-expected.txt
index 1c94220c7f29..6cc630b55bd8 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/svg/animations/animateMotion-spline-invalid-keyTimes-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/animations/animateMotion-spline-invalid-keyTimes-expected.txt
@@ -1,3 +1,3 @@
-FAIL keyTimes does not end with one, calcMode=spline assert_equals: motion path not applied expected 0 but got -10
+PASS keyTimes does not end with one, calcMode=spline
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-media-dynamic-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-media-dynamic-expected.txt
index 83cccce10a03..59051c3044a0 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-media-dynamic-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-media-dynamic-expected.txt
@@ -1,5 +1,5 @@
-FAIL Changing the media attribute updates the associated stylesheet assert_equals: fill should switch once the second sheet's media matches expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
-FAIL Removing the media attribute updates the associated stylesheet assert_equals: removing the media attribute should make the rule apply expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
+PASS Changing the media attribute updates the associated stylesheet
+PASS Removing the media attribute updates the associated stylesheet
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-type-dynamic-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-type-dynamic-expected.txt
index d2211c6e4944..313644a41c58 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-type-dynamic-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/styling/attr-style-type-dynamic-expected.txt
@@ -1,6 +1,6 @@
PASS Initial state: invalid type leaves the sheet unprocessed
-FAIL Changing the type from invalid to valid creates the stylesheet assert_equals: sheet should be created once the type becomes CSS expected 1 but got 0
+PASS Changing the type from invalid to valid creates the stylesheet
PASS Changing the type from valid to invalid removes the stylesheet
-FAIL Removing the type attribute restores the default CSS handling assert_equals: sheet should be created once the type attribute is removed expected 1 but got 0
+PASS Removing the type attribute restores the default CSS handling
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-expected.html b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-expected.html
new file mode 100644
index 000000000000..0798211e668a
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-expected.html
@@ -0,0 +1,17 @@
+
+
+
+
SVG text: combining marks on a textPath shape as one typographic character (reference)
+
+
+
+
+
+
+
+ café exposé
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-ref.html b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-ref.html
new file mode 100644
index 000000000000..0798211e668a
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks-ref.html
@@ -0,0 +1,17 @@
+
+
+
+SVG text: combining marks on a textPath shape as one typographic character (reference)
+
+
+
+
+
+
+
+ café exposé
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks.html b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks.html
new file mode 100644
index 000000000000..7ab7b5361916
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/text/reftests/textpath-combining-marks.html
@@ -0,0 +1,23 @@
+
+
+
+
+SVG text: combining marks on a textPath shape as one typographic character
+
+
+
+
+
+
+
+
+
+
+ café exposé
+
+
+
+
+
diff --git a/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt b/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt
index 9688c4fddf4b..cbfd72377605 100644
--- a/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt
+++ b/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt
@@ -184,89 +184,173 @@ Internal Properties:
Evaluating expression...
Getting displayable properties...
Properties:
- "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "instancePublicProperty" => "instancePublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
- "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => get "get #parentInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => get "get #parentInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => set "set #parentInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateMethod" => "#parentInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => set "set #parentInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "instancePublicProperty" => "instancePublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
+ "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
-- Running test case: Runtime.getDisplayableProperties.Private.Instance.Child
Evaluating expression...
Getting displayable properties...
Properties:
- "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#instancePrivateProperty" => "instancePrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "instancePublicProperty" => "instancePublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
- "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => get "get #parentInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => get "get #parentInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => set "set #parentInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateMethod" => "#parentInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => set "set #parentInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetter" => get "get #childInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childInstancePrivateGetterSetter" => get "get #childInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetterSetter" => set "set #childInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateMethod" => "#childInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childInstancePrivateSetter" => set "set #childInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { child }" (function) [isOwn | isPrivate]
+ "instancePublicProperty" => "instancePublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
+ "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
-- Running test case: Runtime.getDisplayableProperties.Private.Constructor.Parent
Evaluating expression...
Getting displayable properties...
Properties:
- "#classPrivateProperty" => "classPrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentClassPrivateProperty" => "parentClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "length" => 0 (number) [configurable | isOwn]
- "name" => "PrivateMembersTestClassParent" (string) [configurable | isOwn]
- "prototype" => "PrivateMembersTestClassParent" (object) [isOwn]
- "classPublicMethod" => "classPublicMethod() { parent }" (function) [writable | configurable | isOwn]
- "classPublicGetter" => get "get classPublicGetter() { parent }" (function) [configurable | isOwn]
- "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => set "set classPublicSetter(x) { parent }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => get "get classPublicGetterSetter() { parent }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { parent }" (function) [configurable | isOwn]
- "parentClassPublicMethod" => "parentClassPublicMethod() { }" (function) [writable | configurable | isOwn]
- "parentClassPublicGetter" => get "get parentClassPublicGetter() { }" (function) [configurable | isOwn]
- "parentClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "parentClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "parentClassPublicSetter" => set "set parentClassPublicSetter(x) { }" (function) [configurable | isOwn]
- "parentClassPublicGetterSetter" => get "get parentClassPublicGetterSetter() { }" (function) [configurable | isOwn]
- "parentClassPublicGetterSetter" => set "set parentClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
- "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
- "classPublicProperty" => "classPublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
- "parentClassPublicProperty" => "parentClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "arguments" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
- "caller" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
- "__proto__" => "function () {\n [native code]\n}" (function) [writable | configurable | isOwn]
+ "#classPrivateProperty" => "classPrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentClassPrivateProperty" => "parentClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => get "get #parentClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => get "get #parentClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => set "set #parentClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateMethod" => "#parentClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => set "set #parentClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "length" => 0 (number) [configurable | isOwn]
+ "name" => "PrivateMembersTestClassParent" (string) [configurable | isOwn]
+ "prototype" => "PrivateMembersTestClassParent" (object) [isOwn]
+ "classPublicMethod" => "classPublicMethod() { parent }" (function) [writable | configurable | isOwn]
+ "classPublicGetter" => get "get classPublicGetter() { parent }" (function) [configurable | isOwn]
+ "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => set "set classPublicSetter(x) { parent }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => get "get classPublicGetterSetter() { parent }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { parent }" (function) [configurable | isOwn]
+ "parentClassPublicMethod" => "parentClassPublicMethod() { }" (function) [writable | configurable | isOwn]
+ "parentClassPublicGetter" => get "get parentClassPublicGetter() { }" (function) [configurable | isOwn]
+ "parentClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "parentClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "parentClassPublicSetter" => set "set parentClassPublicSetter(x) { }" (function) [configurable | isOwn]
+ "parentClassPublicGetterSetter" => get "get parentClassPublicGetterSetter() { }" (function) [configurable | isOwn]
+ "parentClassPublicGetterSetter" => set "set parentClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
+ "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
+ "classPublicProperty" => "classPublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
+ "parentClassPublicProperty" => "parentClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "arguments" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
+ "caller" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
+ "__proto__" => "function () {\n [native code]\n}" (function) [writable | configurable | isOwn]
-- Running test case: Runtime.getDisplayableProperties.Private.Constructor.Child
Evaluating expression...
Getting displayable properties...
Properties:
- "#classPrivateProperty" => "classPrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "length" => 0 (number) [configurable | isOwn]
- "name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
- "prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
- "classPublicMethod" => "classPublicMethod() { child }" (function) [writable | configurable | isOwn]
- "classPublicGetter" => get "get classPublicGetter() { child }" (function) [configurable | isOwn]
- "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => set "set classPublicSetter(x) { child }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => get "get classPublicGetterSetter() { child }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { child }" (function) [configurable | isOwn]
- "childClassPublicMethod" => "childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
- "childClassPublicGetter" => get "get childClassPublicGetter() { }" (function) [configurable | isOwn]
- "childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "childClassPublicSetter" => set "set childClassPublicSetter(x) { }" (function) [configurable | isOwn]
- "childClassPublicGetterSetter" => get "get childClassPublicGetterSetter() { }" (function) [configurable | isOwn]
- "childClassPublicGetterSetter" => set "set childClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
- "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
- "classPublicProperty" => "classPublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
- "childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "arguments" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
- "caller" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
- "__proto__" => "" (function class) [writable | configurable | isOwn]
+ "#classPrivateProperty" => "classPrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childClassPrivateGetter" => get "get #childClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => get "get #childClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => set "set #childClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateMethod" => "#childClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => set "set #childClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { child }" (function) [isOwn | isPrivate]
+ "length" => 0 (number) [configurable | isOwn]
+ "name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
+ "prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
+ "classPublicMethod" => "classPublicMethod() { child }" (function) [writable | configurable | isOwn]
+ "classPublicGetter" => get "get classPublicGetter() { child }" (function) [configurable | isOwn]
+ "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => set "set classPublicSetter(x) { child }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => get "get classPublicGetterSetter() { child }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { child }" (function) [configurable | isOwn]
+ "childClassPublicMethod" => "childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
+ "childClassPublicGetter" => get "get childClassPublicGetter() { }" (function) [configurable | isOwn]
+ "childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "childClassPublicSetter" => set "set childClassPublicSetter(x) { }" (function) [configurable | isOwn]
+ "childClassPublicGetterSetter" => get "get childClassPublicGetterSetter() { }" (function) [configurable | isOwn]
+ "childClassPublicGetterSetter" => set "set childClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
+ "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
+ "classPublicProperty" => "classPublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
+ "childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "arguments" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
+ "caller" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
+ "__proto__" => "" (function class) [writable | configurable | isOwn]
-- Running test case: Runtime.getDisplayableProperties.Private.Prototype.Parent
Evaluating expression...
Getting displayable properties...
Properties:
+ "#classPrivateGetter" => get "get #classPrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => get "get #parentClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => get "get #parentClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => set "set #parentClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateMethod" => "#parentClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => set "set #parentClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
"constructor" => "" (function class) [writable | configurable | isOwn]
"instancePublicMethod" => "instancePublicMethod() { parent }" (function) [writable | configurable | isOwn]
"instancePublicGetter" => get "get instancePublicGetter() { parent }" (function) [configurable | isOwn]
@@ -288,6 +372,20 @@ Properties:
Evaluating expression...
Getting displayable properties...
Properties:
+ "#childClassPrivateGetter" => get "get #childClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => get "get #childClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => set "set #childClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateMethod" => "#childClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => set "set #childClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { child }" (function) [isOwn | isPrivate]
"constructor" => "" (function class) [writable | configurable | isOwn]
"instancePublicMethod" => "instancePublicMethod() { child }" (function) [writable | configurable | isOwn]
"instancePublicGetter" => get "get instancePublicGetter() { child }" (function) [configurable | isOwn]
diff --git a/LayoutTests/inspector/runtime/getProperties-expected.txt b/LayoutTests/inspector/runtime/getProperties-expected.txt
index f5f04a2239da..eb2d8ac3fe14 100644
--- a/LayoutTests/inspector/runtime/getProperties-expected.txt
+++ b/LayoutTests/inspector/runtime/getProperties-expected.txt
@@ -158,85 +158,169 @@ Internal Properties:
Evaluating expression...
Getting own properties...
Properties:
- "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "instancePublicProperty" => "instancePublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
- "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => get "get #parentInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => get "get #parentInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => set "set #parentInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateMethod" => "#parentInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => set "set #parentInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "instancePublicProperty" => "instancePublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
+ "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
-- Running test case: Runtime.getProperties.Private.Instance.Child
Evaluating expression...
Getting own properties...
Properties:
- "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#instancePrivateProperty" => "instancePrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "instancePublicProperty" => "instancePublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
- "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateProperty" => "instancePrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => get "get #parentInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => get "get #parentInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateGetterSetter" => set "set #parentInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateMethod" => "#parentInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentInstancePrivateSetter" => set "set #parentInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetter" => get "get #childInstancePrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childInstancePrivateGetterSetter" => get "get #childInstancePrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateGetterSetter" => set "set #childInstancePrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateMethod" => "#childInstancePrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childInstancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childInstancePrivateSetter" => set "set #childInstancePrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => get "get #instancePrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => get "get #instancePrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateGetterSetter" => set "set #instancePrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateMethod" => "#instancePrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#instancePrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#instancePrivateSetter" => set "set #instancePrivateSetter(x) { child }" (function) [isOwn | isPrivate]
+ "instancePublicProperty" => "instancePublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
+ "parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
-- Running test case: Runtime.getProperties.Private.Constructor.Parent
Evaluating expression...
Getting own properties...
Properties:
- "#classPrivateProperty" => "classPrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#parentClassPrivateProperty" => "parentClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "length" => 0 (number) [configurable | isOwn]
- "name" => "PrivateMembersTestClassParent" (string) [configurable | isOwn]
- "prototype" => "PrivateMembersTestClassParent" (object) [isOwn]
- "classPublicMethod" => "classPublicMethod() { parent }" (function) [writable | configurable | isOwn]
- "classPublicGetter" => get "get classPublicGetter() { parent }" (function) [configurable | isOwn]
- "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => set "set classPublicSetter(x) { parent }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => get "get classPublicGetterSetter() { parent }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { parent }" (function) [configurable | isOwn]
- "parentClassPublicMethod" => "parentClassPublicMethod() { }" (function) [writable | configurable | isOwn]
- "parentClassPublicGetter" => get "get parentClassPublicGetter() { }" (function) [configurable | isOwn]
- "parentClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "parentClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "parentClassPublicSetter" => set "set parentClassPublicSetter(x) { }" (function) [configurable | isOwn]
- "parentClassPublicGetterSetter" => get "get parentClassPublicGetterSetter() { }" (function) [configurable | isOwn]
- "parentClassPublicGetterSetter" => set "set parentClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
- "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
- "classPublicProperty" => "classPublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
- "parentClassPublicProperty" => "parentClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "function () {\n [native code]\n}" (function) [writable | configurable | isOwn]
+ "#classPrivateProperty" => "classPrivatePropertyValue parent" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#parentClassPrivateProperty" => "parentClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => get "get #parentClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => get "get #parentClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => set "set #parentClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateMethod" => "#parentClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => set "set #parentClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "length" => 0 (number) [configurable | isOwn]
+ "name" => "PrivateMembersTestClassParent" (string) [configurable | isOwn]
+ "prototype" => "PrivateMembersTestClassParent" (object) [isOwn]
+ "classPublicMethod" => "classPublicMethod() { parent }" (function) [writable | configurable | isOwn]
+ "classPublicGetter" => get "get classPublicGetter() { parent }" (function) [configurable | isOwn]
+ "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => set "set classPublicSetter(x) { parent }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => get "get classPublicGetterSetter() { parent }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { parent }" (function) [configurable | isOwn]
+ "parentClassPublicMethod" => "parentClassPublicMethod() { }" (function) [writable | configurable | isOwn]
+ "parentClassPublicGetter" => get "get parentClassPublicGetter() { }" (function) [configurable | isOwn]
+ "parentClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "parentClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "parentClassPublicSetter" => set "set parentClassPublicSetter(x) { }" (function) [configurable | isOwn]
+ "parentClassPublicGetterSetter" => get "get parentClassPublicGetterSetter() { }" (function) [configurable | isOwn]
+ "parentClassPublicGetterSetter" => set "set parentClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
+ "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
+ "classPublicProperty" => "classPublicPropertyValue parent" (string) [writable | enumerable | configurable | isOwn]
+ "parentClassPublicProperty" => "parentClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "function () {\n [native code]\n}" (function) [writable | configurable | isOwn]
-- Running test case: Runtime.getProperties.Private.Constructor.Child
Evaluating expression...
Getting own properties...
Properties:
- "#classPrivateProperty" => "classPrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
- "length" => 0 (number) [configurable | isOwn]
- "name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
- "prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
- "classPublicMethod" => "classPublicMethod() { child }" (function) [writable | configurable | isOwn]
- "classPublicGetter" => get "get classPublicGetter() { child }" (function) [configurable | isOwn]
- "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "classPublicSetter" => set "set classPublicSetter(x) { child }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => get "get classPublicGetterSetter() { child }" (function) [configurable | isOwn]
- "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { child }" (function) [configurable | isOwn]
- "childClassPublicMethod" => "childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
- "childClassPublicGetter" => get "get childClassPublicGetter() { }" (function) [configurable | isOwn]
- "childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
- "childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
- "childClassPublicSetter" => set "set childClassPublicSetter(x) { }" (function) [configurable | isOwn]
- "childClassPublicGetterSetter" => get "get childClassPublicGetterSetter() { }" (function) [configurable | isOwn]
- "childClassPublicGetterSetter" => set "set childClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
- "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
- "classPublicProperty" => "classPublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
- "childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
- "__proto__" => "" (function class) [writable | configurable | isOwn]
+ "#classPrivateProperty" => "classPrivatePropertyValue child" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | isPrivate]
+ "#childClassPrivateGetter" => get "get #childClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => get "get #childClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => set "set #childClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateMethod" => "#childClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => set "set #childClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { child }" (function) [isOwn | isPrivate]
+ "length" => 0 (number) [configurable | isOwn]
+ "name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
+ "prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
+ "classPublicMethod" => "classPublicMethod() { child }" (function) [writable | configurable | isOwn]
+ "classPublicGetter" => get "get classPublicGetter() { child }" (function) [configurable | isOwn]
+ "classPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "classPublicSetter" => set "set classPublicSetter(x) { child }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => get "get classPublicGetterSetter() { child }" (function) [configurable | isOwn]
+ "classPublicGetterSetter" => set "set classPublicGetterSetter(x) { child }" (function) [configurable | isOwn]
+ "childClassPublicMethod" => "childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
+ "childClassPublicGetter" => get "get childClassPublicGetter() { }" (function) [configurable | isOwn]
+ "childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
+ "childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
+ "childClassPublicSetter" => set "set childClassPublicSetter(x) { }" (function) [configurable | isOwn]
+ "childClassPublicGetterSetter" => get "get childClassPublicGetterSetter() { }" (function) [configurable | isOwn]
+ "childClassPublicGetterSetter" => set "set childClassPublicGetterSetter(x) { }" (function) [configurable | isOwn]
+ "toString" => "toString() { return \"\"; }" (function) [writable | configurable | isOwn]
+ "classPublicProperty" => "classPublicPropertyValue child" (string) [writable | enumerable | configurable | isOwn]
+ "childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
+ "__proto__" => "" (function class) [writable | configurable | isOwn]
-- Running test case: Runtime.getProperties.Private.Prototype.Parent
Evaluating expression...
Getting own properties...
Properties:
+ "#classPrivateGetter" => get "get #classPrivateGetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { parent }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { parent }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => get "get #parentClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => get "get #parentClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateGetterSetter" => set "set #parentClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateMethod" => "#parentClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#parentClassPrivateSetter" => set "set #parentClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
"constructor" => "" (function class) [writable | configurable | isOwn]
"instancePublicMethod" => "instancePublicMethod() { parent }" (function) [writable | configurable | isOwn]
"instancePublicGetter" => get "get instancePublicGetter() { parent }" (function) [configurable | isOwn]
@@ -258,6 +342,20 @@ Properties:
Evaluating expression...
Getting own properties...
Properties:
+ "#childClassPrivateGetter" => get "get #childClassPrivateGetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => get "get #childClassPrivateGetterSetter() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateGetterSetter" => set "set #childClassPrivateGetterSetter(x) { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateMethod" => "#childClassPrivateMethod() { }" (function) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#childClassPrivateSetter" => set "set #childClassPrivateSetter(x) { }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => get "get #classPrivateGetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetter" => set undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => get "get #classPrivateGetterSetter() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateGetterSetter" => set "set #classPrivateGetterSetter(x) { child }" (function) [isOwn | isPrivate]
+ "#classPrivateMethod" => "#classPrivateMethod() { child }" (function) [isOwn | isPrivate]
+ "#classPrivateSetter" => get undefined (undefined) [isOwn | isPrivate]
+ "#classPrivateSetter" => set "set #classPrivateSetter(x) { child }" (function) [isOwn | isPrivate]
"constructor" => "" (function class) [writable | configurable | isOwn]
"instancePublicMethod" => "instancePublicMethod() { child }" (function) [writable | configurable | isOwn]
"instancePublicGetter" => get "get instancePublicGetter() { child }" (function) [configurable | isOwn]
diff --git a/LayoutTests/ipc/coreipc.js b/LayoutTests/ipc/coreipc.js
index 03ba39ec36c5..a15c63ed87c4 100644
--- a/LayoutTests/ipc/coreipc.js
+++ b/LayoutTests/ipc/coreipc.js
@@ -759,6 +759,10 @@ export class ArgumentSerializer {
if (argument === null) {
return [];
} else throw new SerializationError(`std::nullptr_t is not null`);
+ case 'std::monostate':
+ if (argument === null) {
+ return [];
+ } else throw new SerializationError(`std::monostate is not null`);
case 'WebCore::SharedMemory::Handle':
case 'WebCore::SharedMemoryHandle':
case 'MachSendRight':
@@ -1199,7 +1203,9 @@ export class ArgumentParser {
return [position, {parsedValue: result, parsedType: 'String'}];
}
case 'std::nullptr_t':
- return [position, {parsedValue: 'null', parsedType: 'std::nullptr_t'}];
+ return [position, {parsedValue: null, parsedType: 'std::nullptr_t'}];
+ case 'std::monostate':
+ return [position, {parsedValue: null, parsedType: 'std::monostate'}];
}
return undefined;
}
diff --git a/LayoutTests/ipc/forged-resource-load-statistics-storage-access-expected.txt b/LayoutTests/ipc/forged-resource-load-statistics-storage-access-expected.txt
new file mode 100644
index 000000000000..dfa02d6ca0b0
--- /dev/null
+++ b/LayoutTests/ipc/forged-resource-load-statistics-storage-access-expected.txt
@@ -0,0 +1,4 @@
+Test that a WebContent process cannot forge a persistent storage-access grant by sending storageAccessUnderTopFrameDomains via NetworkConnectionToWebProcess::ResourceLoadStatisticsUpdated.
+
+PASS: no storage-access grant was created from forged statistics
+
diff --git a/LayoutTests/ipc/forged-resource-load-statistics-storage-access.html b/LayoutTests/ipc/forged-resource-load-statistics-storage-access.html
new file mode 100644
index 000000000000..1f5fdad59173
--- /dev/null
+++ b/LayoutTests/ipc/forged-resource-load-statistics-storage-access.html
@@ -0,0 +1,110 @@
+
+
+
+Test that a WebContent process cannot forge a persistent storage-access grant by sending
+storageAccessUnderTopFrameDomains via NetworkConnectionToWebProcess::ResourceLoadStatisticsUpdated.
+
+
+
+
diff --git a/LayoutTests/ipc/loadping-firstpartyforcookies-message-check-expected.txt b/LayoutTests/ipc/loadping-firstpartyforcookies-message-check-expected.txt
new file mode 100644
index 000000000000..b7c9dd005623
--- /dev/null
+++ b/LayoutTests/ipc/loadping-firstpartyforcookies-message-check-expected.txt
@@ -0,0 +1,3 @@
+
+PASS LoadPing rejects forged firstPartyForCookies via MESSAGE_CHECK
+
diff --git a/LayoutTests/ipc/loadping-firstpartyforcookies-message-check.html b/LayoutTests/ipc/loadping-firstpartyforcookies-message-check.html
new file mode 100644
index 000000000000..8b5c383161f3
--- /dev/null
+++ b/LayoutTests/ipc/loadping-firstpartyforcookies-message-check.html
@@ -0,0 +1,149 @@
+
+Test that LoadPing validates firstPartyForCookies via MESSAGE_CHECK
+
+
+
+
+
diff --git a/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change-expected.txt b/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change-expected.txt
new file mode 100644
index 000000000000..654ddf7f17ef
--- /dev/null
+++ b/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change-expected.txt
@@ -0,0 +1 @@
+This test passes if it does not crash.
diff --git a/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change.html b/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change.html
new file mode 100644
index 000000000000..c692c667b7f7
--- /dev/null
+++ b/LayoutTests/ipc/networksindexeddb-close-connection-during-version-change.html
@@ -0,0 +1,117 @@
+
+This test passes if it does not crash.
+
diff --git a/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure-expected.txt b/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure-expected.txt
new file mode 100644
index 000000000000..69cfc5a98db7
--- /dev/null
+++ b/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure-expected.txt
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure.html b/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure.html
new file mode 100644
index 000000000000..960a47394d31
--- /dev/null
+++ b/LayoutTests/ipc/rgba16f-getpixelbuffer-colorspace-mismatch-heap-disclosure.html
@@ -0,0 +1,120 @@
+
+
+
diff --git a/LayoutTests/ipc/use-redirection-for-current-navigation-message-check-expected.txt b/LayoutTests/ipc/use-redirection-for-current-navigation-message-check-expected.txt
new file mode 100644
index 000000000000..8155bcd41270
--- /dev/null
+++ b/LayoutTests/ipc/use-redirection-for-current-navigation-message-check-expected.txt
@@ -0,0 +1,2 @@
+PASS: UseRedirectionForCurrentNavigation with non-redirect response was rejected
+
diff --git a/LayoutTests/ipc/use-redirection-for-current-navigation-message-check.html b/LayoutTests/ipc/use-redirection-for-current-navigation-message-check.html
new file mode 100644
index 000000000000..f22480e8d0fc
--- /dev/null
+++ b/LayoutTests/ipc/use-redirection-for-current-navigation-message-check.html
@@ -0,0 +1,71 @@
+
+
+
+
+
diff --git a/LayoutTests/media/media-source/media-source-fudge-factor-expected.txt b/LayoutTests/media/media-source/media-source-fudge-factor-expected.txt
deleted file mode 100644
index cb7f1408b773..000000000000
--- a/LayoutTests/media/media-source/media-source-fudge-factor-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-
-RUN(video.src = URL.createObjectURL(source))
-EVENT(loadedmetadata)
-EVENT(update)
-Samples with presentation times after currentTime should not cause loadedData.
-EVENT(update)
-EXPECTED (video.readyState == '1') OK
-Samples with presentation times very close to currentTime should cause loadedData.
-EVENT(loadeddata)
-EVENT(update)
-EXPECTED (video.readyState == '2') OK
-Samples with presentation end times very close to currentTime should not cause canPlay.
-EVENT(update)
-EXPECTED (video.readyState == '2') OK
-Continuous samples with presentation end times after currentTime should cause canPlay.
-EVENT(canplay)
-EXPECTED (video.readyState >= '3') OK
-END OF TEST
-
diff --git a/LayoutTests/media/media-source/media-source-fudge-factor.html b/LayoutTests/media/media-source/media-source-fudge-factor.html
deleted file mode 100644
index e0c0a6697da4..000000000000
--- a/LayoutTests/media/media-source/media-source-fudge-factor.html
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
- media-source-fudge-factor
-
-
-
-
-
-
-
-
diff --git a/LayoutTests/media/media-source/media-source-gap-policy-expected.txt b/LayoutTests/media/media-source/media-source-gap-policy-expected.txt
new file mode 100644
index 000000000000..631529d4e6fb
--- /dev/null
+++ b/LayoutTests/media/media-source/media-source-gap-policy-expected.txt
@@ -0,0 +1,30 @@
+
+RUN(video.src = URL.createObjectURL(source))
+EVENT(update)
+EVENT(loadedmetadata)
+EVENT(update)
+EVENT(update)
+=== Start-of-stream allowance (1 s) ===
+Video [1500, 4000]: 1.5 s start gap > 1 s, readyState stays HAVE_METADATA.
+EVENT(update)
+EXPECTED (video.readyState == '1') OK
+Video [500, 1000]: 500 ms start gap <= 1 s, canplay fires.
+EVENT(canplay)
+EVENT(update)
+EXPECTED (video.readyState >= '3') OK
+=== Mid-stream gap tolerance (125 ms) ===
+Remove audio [1000, 1500) so it no longer bridges the 500 ms video gap.
+EVENT(update)
+500 ms gap > 125 ms tolerance: readyState below HAVE_ENOUGH_DATA.
+EXPECTED (video.readyState < '4') OK
+=== Audio-covered gap tolerance (250 ms) ===
+Re-append audio [1000, 1500): audio bridges the video gap.
+EVENT(update)
+500 ms gap > 250 ms audio-covered tolerance: readyState still below HAVE_ENOUGH_DATA.
+EXPECTED (video.readyState < '4') OK
+Append video [1200, 1500] to shrink the gap to 200 ms: canplaythrough fires.
+EVENT(canplaythrough)
+EVENT(update)
+EXPECTED (video.readyState == '4') OK
+END OF TEST
+
diff --git a/LayoutTests/media/media-source/media-source-gap-policy.html b/LayoutTests/media/media-source/media-source-gap-policy.html
new file mode 100644
index 000000000000..a1a7a4042153
--- /dev/null
+++ b/LayoutTests/media/media-source/media-source-gap-policy.html
@@ -0,0 +1,88 @@
+
+
+
+ media-source-gap-policy
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion-expected.txt b/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion-expected.txt
new file mode 100644
index 000000000000..6705aa6c2453
--- /dev/null
+++ b/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion-expected.txt
@@ -0,0 +1,16 @@
+Tests that navigation.navigate() returns a valid NavigationResult when argument conversion throws
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof result is 'object'
+PASS 'committed' in result is true
+PASS 'finished' in result is true
+PASS result.committed instanceof Promise is true
+PASS result.finished instanceof Promise is true
+PASS committedError.message is "test error"
+PASS finishedError.message is "test error"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion.html b/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion.html
new file mode 100644
index 000000000000..5e60aa03bfce
--- /dev/null
+++ b/LayoutTests/navigation-api/navigation-navigate-throwing-argument-conversion.html
@@ -0,0 +1,39 @@
+
+
+
diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations
index a889ed73c5e9..3683fe80edfd 100644
--- a/LayoutTests/platform/ios/TestExpectations
+++ b/LayoutTests/platform/ios/TestExpectations
@@ -2377,7 +2377,7 @@ webkit.org/b/148806 imported/w3c/web-platform-tests/css/css-multicol/multicol-sp
fast/dom/linkify-phone-numbers.html [ Pass ]
accessibility/table-exposure-updates-dynamically.html [ Pass ]
-accessibility/accessibility-node-reparent.html [ Pass ]
+accessibility/accessibility-node-reparent.html [ Pass Timeout ] # rdar://178168616
accessibility/area-element-bounding-box.html [ Pass ]
accessibility/aria-actions.html [ Pass ]
accessibility/aria-owns-text-stitching.html [ Pass ]
@@ -2408,7 +2408,7 @@ accessibility/canvas-drawFocusIfNeeded-bounds-with-object-fit.html [ Pass ]
accessibility/canvas-drawFocusIfNeeded-bounds-with-transform.html [ Pass ]
accessibility/changing-aria-hidden-with-display-none-parent.html [ Pass ]
accessibility/checkbox-mixed-value.html [ Pass ]
-accessibility/clip-path-bounding-box.html [ Pass ]
+accessibility/clip-path-bounding-box.html [ Pass Failure Timeout ] # rdar://177742349, rdar://179387348
accessibility/css-content-alt-text.html [ Pass ]
accessibility/dialog-slotted-content.html [ Pass ]
accessibility/dirty-relations-and-modal-tree-update-crash.html [ Pass ]
@@ -2470,7 +2470,7 @@ accessibility/nested-custom-element-accname.html [ Pass ]
accessibility/node-only-inert-object.html [ Pass ]
accessibility/node-only-object-element-rect.html [ Pass ]
accessibility/checkbox-radio-element-rect.html [ Pass ]
-accessibility/opacity-0-bounding-box.html [ Pass ]
+accessibility/opacity-0-bounding-box.html [ Pass Failure ] # rdar://177981724
accessibility/out-of-bounds-rowspan.html [ Pass ]
accessibility/out-of-bounds-rowspan-display-none.html [ Pass ]
accessibility/out-of-bounds-rowspan-aria-hidden.html [ Pass ]
@@ -3274,7 +3274,7 @@ fast/loader/plain-text-document-dark-mode.html [ Pass ]
fast/forms/auto-fill-button/caps-lock-indicator-should-be-visible-after-hiding-auto-fill-strong-password-button.html [ Pass ]
fast/forms/auto-fill-button/caps-lock-indicator-should-not-be-visible-when-auto-fill-strong-password-button-is-visible.html [ Pass ]
-fast/forms/password-scrolled-after-caps-lock-toggled.html [ Pass ]
+fast/forms/password-scrolled-after-caps-lock-toggled.html [ Pass Timeout Failure ]
# REGRESSION (iOS 13): Three cookie layout tests failing
http/wpt/beacon/cors/cors-preflight-cookie.html [ Failure ]
@@ -3555,7 +3555,7 @@ http/wpt/mediarecorder/mute-tracks.html [ Pass Failure ]
# rdar://80396502 ([ iOS15 ] http/wpt/mediarecorder/pause-recording.html is a flaky crash)
http/wpt/mediarecorder/pause-recording.html [ Pass Crash ]
-accessibility/misspelling-range.html [ Pass ]
+accessibility/misspelling-range.html [ Pass Failure ] # rdar://131398291
# Behavior of navigator-language-ru changed in iOS 15.
fast/text/international/system-language/navigator-language/navigator-language-ru.html [ Failure ]
@@ -7751,7 +7751,7 @@ webkit.org/b/290670 imported/w3c/web-platform-tests/css/css-viewport/zoom/relati
webkit.org/b/290767 [ x86_64 ] imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-denormals.https.window.html [ Failure ]
-webkit.org/b/290790 editing/selection/ios/show-selection-in-transformed-container.html [ Failure ]
+webkit.org/b/290790 editing/selection/ios/show-selection-in-transformed-container.html [ Pass Failure Timeout ] # rdar://177980999
webkit.org/b/290794 fast/viewport/ios/content-visibility-layout-viewport-during-unstable-scroll.html [ Failure ]
@@ -8417,7 +8417,7 @@ fast/dom/HTMLLinkElement/prefetch-too-many-clients.html [ Skip ]
fast/dynamic/crash-paint-no-documentElement-renderer.html [ Skip ]
fast/editing/ruby-with-edited-text-crash.html [ Skip ]
fast/events/key-events-in-frame.html [ Skip ]
-fast/forms/textarea/textarea-state-restore.html [ Pass Timeout ]
+fast/forms/textarea/textarea-state-restore.html [ Pass Timeout Failure ] # rdar://179387373
[ Debug ] fast/layers/top-layer-ancestor-opacity-and-transform-crash.html [ Skip ]
[ Release ] fast/mediastream/MediaStream-page-muted.html [ Pass Timeout ]
fast/table/double-height-table-no-tbody.html [ Skip ]
@@ -8464,7 +8464,7 @@ webkit.org/b/316014 [ Debug ] fast/dom/move-embedded-during-update.html [ Pass F
webkit.org/b/316218 fast/scrolling/ios/scroll-into-view-smooth-after-snap.html [ Pass Failure ]
-webkit.org/b/316228 fast/dom/Orientation/no-orientation-change-event-when-unparenting-view.html [ Failure ]
+webkit.org/b/316228 fast/dom/Orientation/no-orientation-change-event-when-unparenting-view.html [ Pass Timeout Failure ]
webkit.org/b/316118 imported/w3c/web-platform-tests/url/IdnaTestV2.any.html [ Failure ]
@@ -8495,6 +8495,105 @@ imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-off
imported/w3c/web-platform-tests/css/css-scroll-snap/input/keyboard-snap-interruption.html [ Skip ] # timeout
+compositing/backing/backing-store-attachment-animating-outside-viewport.html [ Pass Failure ] # rdar://178675997
+compositing/color-matching/image-color-matching.html [ Pass Crash ] # rdar://178675338
+editing/editable-region/hit-test-fixed.html [ Pass Failure ] # rdar://178675880
+editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html [ Pass Failure ] # rdar://178172917
+editing/input/cocoa/autocorrect-on.html [ Pass Timeout ]
+editing/input/cocoa/extended-proofreading.html [ Pass Timeout ] # rdar://177981315
+editing/input/ios/compose-accent-with-hardware-keyboard-when-preventing-keydown.html [ Pass Failure Timeout ] # rdar://176615540
+editing/selection/ios/caret-rect-after-inserting-newlines-in-textarea.html [ Pass Timeout Crash ] # rdar://177980999
+editing/selection/ios/select-text-by-long-press-with-focused-element.html [ Pass Timeout ] # rdar://180007873
+editing/selection/ios/select-text-by-long-press-with-hardware-keyboard.html [ Pass Timeout ] # rdar://180007873
+editing/selection/ios/select-word-for-replacement-extends-grammar-marker.html [ Pass Timeout ] # rdar://180007873
+editing/selection/ios/selection-clip-in-position-relative-text-field.html [ Pass Timeout ] # rdar://177980999
+editing/selection/ios/selection-moves-between-composited-layers.html [ Pass Timeout Crash ] # rdar://177980999, rdar://179387140
+editing/selection/ios/show-edit-menu-with-transparent-caret.html [ Pass Timeout ] # rdar://177980999
+editing/selection/ios/show-grammar-replacements-on-tap.html [ Pass Timeout ] # rdar://177980999
+editing/selection/ios/tap-focused-input-clears-outside-selection.html [ Timeout ] # rdar://180007798
+editing/text-placeholder/caret-before-zero-width-placeholder-in-content-editable-start-of-word.html [ Pass Timeout ] # rdar://178158441
+fast/dynamic/anchor-lock.html [ Pass Failure ] # rdar://178675751
+fast/events/autoscroll-when-input-is-offscreen.html [ Pass Failure ]
+fast/events/ios/pdf-modifer-key-down-crash.html [ Pass Crash ]
+fast/forms/datalist/data-list-search-input-with-appearance-none.html [ Timeout ] # rdar://178168549
+fast/forms/datalist/datalist-textinput-dynamically-add-options-on-keydown.html [ Pass Timeout ]
+fast/forms/ios/select-option-update-1000.html [ Failure Timeout ] # rdar://178168662
+fast/images/imageDocument-title.html [ Pass Crash ] # rdar://178675308
+fast/mediastream/audio-session-category-capture-audio-context.html [ Pass Timeout ]
+fast/mediastream/media-stream-video-track-interrupted.html [ Pass Failure ] # rdar://178673961
+fast/mediastream/mediastreamtrack-clone-muted.html [ Pass Timeout ] # rdar://178215298
+fast/screen-orientation/orientation-in-resize-event.html [ Pass Failure Timeout ] # rdar://177741597
+fast/scrolling/scroll-anchoring/heuristic-enabled-below-threshold.html [ Pass Failure ] # rdar://178168995
+fast/text-extraction/text-extraction-scroll-fallback-to-large-container.html [ Pass Failure ] # rdar://178169238
+fast/viewport/ios/shrink-to-fit-for-page-without-viewport-meta.html [ Failure ] # rdar://178168569
+fast/viewport/ios/width-is-device-width-overflowing-body-overflow-hidden-tall.html [ Failure ] # rdar://178168569
+fast/visual-viewport/ios/visual-viewport-dimensions-during-scroll-with-keyboard.html [ Timeout ] # rdar://178016084
+http/tests/cache/cancel-multiple-post-xhrs.html [ Pass Failure ] # rdar://178676120
+http/tests/download/anchor-download-redirect-cross-origin.html [ Pass Crash ] # rdar://178214780
+http/tests/privateClickMeasurement/database-disabled-in-ephemeral-session.html [ Pass Timeout Crash ] # rdar://176608751, rdar://179387095
+http/tests/security/referrer-policy-header-invalid.html [ Pass Timeout ] # rdar://178168636
+http/tests/site-isolation/datalist-cross-origin-iframe.html [ Timeout ] # rdar://179387257
+http/tests/site-isolation/selection-focus.html [ ImageOnlyFailure ] # rdar://163216880
+http/tests/site-isolation/type-in-cross-origin-iframe.html [ Failure Timeout ] # rdar://178168718
+http/wpt/service-workers/persistent-modules.html [ Pass Failure ] # rdar://178676392
+imported/w3c/web-platform-tests/IndexedDB/interleaved-cursors-small.any.html [ Pass Failure ] # rdar://178158917
+imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple.any.html [ Pass Failure ] # rdar://178158917
+imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple.any.worker.html [ Pass Failure ] # rdar://178158917
+imported/w3c/web-platform-tests/css/css-anchor-position/scroll-to-anchored-fixed-000.html [ Pass ImageOnlyFailure ] # rdar://178676781
+imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-033.html [ Pass Crash ImageOnlyFailure ]
+imported/w3c/web-platform-tests/css/css-shapes/spec-examples/shape-outside-011.html [ Pass Failure ] # rdar://178676728
+imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-position-auto-002.html [ Pass ImageOnlyFailure ] # rdar://178676895
+imported/w3c/web-platform-tests/css/css-view-transitions/view-transition-waituntil-finished-promise.html [ Pass Failure ] # rdar://178676670
+imported/w3c/web-platform-tests/css/css-writing-modes/text-orientation-upright-srl-018.xht [ Pass ImageOnlyFailure ] # rdar://178676919
+imported/w3c/web-platform-tests/css/cssom-view/scrollIntoView-smooth.html [ Pass Failure ] # rdar://178676605
+imported/w3c/web-platform-tests/custom-elements/reactions/Document.html [ Pass Crash ] # rdar://178158852
+imported/w3c/web-platform-tests/html/browsers/browsing-the-web/navigating-across-documents/cross-origin-top-navigation-with-user-activation-in-parent.window.html [ Pass Failure ] # rdar://178214939
+imported/w3c/web-platform-tests/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html [ Failure ] # rdar://178012093
+imported/w3c/web-platform-tests/html/cross-origin-embedder-policy/anonymous-iframe/cookie.tentative.https.window.html [ Pass Crash Timeout ] # rdar://178158581
+imported/w3c/web-platform-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/video-default-object-height-constrained-by-max-width.html [ Crash ] # rdar://178169483
+imported/w3c/web-platform-tests/html/rendering/widgets/shadow-dom.html [ Pass Failure ] # rdar://178546346
+imported/w3c/web-platform-tests/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html [ Failure ] # rdar://178018070
+imported/w3c/web-platform-tests/html/semantics/forms/form-submission-target/form-target-blank-useractivation.html [ Pass Failure ] # rdar://180007963
+imported/w3c/web-platform-tests/navigation-api/navigate-event/defer/tentative/defer-same-document.html [ Pass Crash ]
+imported/w3c/web-platform-tests/scroll-to-text-fragment/redirects.html [ Pass Failure ] # rdar://178158764
+imported/w3c/web-platform-tests/shadow-dom/event-on-pseudo-element-crash.html [ Pass Timeout ] # rdar://179387553
+imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp-cross-realm.html [ Pass Failure ] # rdar://179388032
+imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-automatic-pull.https.html [ Pass Failure ] # rdar://178172495
+media/audio-session-category-play-unmute-pause.html [ Failure ] # rdar://178158431
+media/media-visible-in-viewport-in-fullscreen.html [ Timeout ] # rdar://178016189
+media/media-vp8-webm-with-poster.html [ Timeout Crash ] # rdar://178016189
+media/video-pause-immediately.html [ Pass Failure ] # rdar://178675666
+media/video-webm-seek-multi-audio-tracks.html [ Timeout ] # rdar://180007922
+quicklook/word-legacy.html [ Failure ] # rdar://174850780
+quicklook/word.html [ Failure ] # rdar://174850780
+svg/filters/feMorphology-negative-radius.html [ Pass Crash ] # rdar://178675229
+webgl/1.0.x/conformance/textures/misc/texture-srgb-upload.html [ Timeout ] # rdar://176399952
+workers/worker-set-delete-terminate-crash.html [ Timeout ] # rdar://178590046
+svg/transforms/nested-svg-transform-attribute-creates-layer.html [ Failure ] # rdar://180457293
+svg/compositing/segment-removed-after-anchor-decomposited-layer-tree.html [ Failure ] # rdar://180457293
+svg/compositing/transform-change-repainting-viewBox-repaintRects.html [ Failure ] # rdar://180457293
+svg/compositing/anonymous-RenderSVGViewportContainer-no-repaints.html [ Failure ] # rdar://180457293
+fast/events/touch/ios/touch-event-regions-layer-tree/svg-image-with-layer-based-svg-engine.html [ Failure ] # rdar://180457293
+fast/events/touch/ios/touch-event-regions-layer-tree/svg-path-with-layer-based-svg-engine.html [ Failure ] # rdar://180457293
+fast/events/touch/ios/touch-event-regions-layer-tree/svg-text-with-layer-based-svg-engine.html [ Failure ] # rdar://180457293
+fast/events/touch/ios/touch-event-regions-layer-tree/mousemove-mouseup.html [ Failure ] # rdar://180457293
+fast/forms/ios/click-should-not-suppress-misspelling.html [ Failure ] # webkit.org/b/318249
+fast/forms/ios/force-gregorian-calendar-for-credit-card-expiry.html [ Failure ] # webkit.org/b/318249
+fast/forms/ios/insert-autofill-suggestion.html [ Failure ] # webkit.org/b/318249
+fast/forms/ios/suppress-software-keyboard-while-focusing-input.html [ Failure ] # webkit.org/b/318249
+editing/selection/ios/do-not-hide-selection-in-visible-field.html [ Timeout ] # webkit.org/b/318250
+editing/selection/ios/update-selection-after-iframe-scroll.html [ Timeout ] # webkit.org/b/318250
+fast/events/ios/autocorrect-with-apostrophe.html [ Timeout ] # webkit.org/b/318251
+fast/events/ios/do-not-show-keyboard-when-focusing-after-blur.html [ Timeout ] # webkit.org/b/318251
+fast/forms/ios/hide-keyboard-on-node-removal.html [ Timeout ] # webkit.org/b/318252
+fast/forms/ios/zoom-to-reveal-focused-element-after-delay.html [ Timeout ] # webkit.org/b/318252
+editing/caret/ios/place-caret-after-autocorrected-word.html [ Failure ] # webkit.org/b/318253
+editing/input/ios/typing-with-inline-predictions.html [ Pass Timeout ] # webkit.org/b/318254
+imported/w3c/web-platform-tests/content-security-policy/inheritance/history.sub.html [ Failure ] # webkit.org/b/318255
+imported/w3c/web-platform-tests/digital-credentials/mdoc/mixed-requests.https.html [ Failure ] # webkit.org/b/318256
+imported/w3c/web-platform-tests/html/semantics/forms/the-input-element/number-constraint-validation.html [ Pass Failure ] # webkit.org/b/318257
+ipc/fecolormatrix-type-values-mismatch-crash.html [ Failure ] # webkit.org/b/318258
+
webkit.org/b/317884 imported/w3c/web-platform-tests/digital-credentials/get-non-fully-active.https.html [ Skip ]
webkit.org/b/318157 [ Debug ] imported/w3c/web-platform-tests/IndexedDB/interleaved-cursors-small.any.sharedworker.html [ Failure ]
diff --git a/LayoutTests/platform/ios/svg/compositing/anonymous-RenderSVGViewportContainer-no-repaints-expected.txt b/LayoutTests/platform/ios/svg/compositing/anonymous-RenderSVGViewportContainer-no-repaints-expected.txt
index 568ce4182ec1..64274d2d4bfe 100644
--- a/LayoutTests/platform/ios/svg/compositing/anonymous-RenderSVGViewportContainer-no-repaints-expected.txt
+++ b/LayoutTests/platform/ios/svg/compositing/anonymous-RenderSVGViewportContainer-no-repaints-expected.txt
@@ -13,16 +13,22 @@
(children 1
(GraphicsLayer
(bounds 784.00 784.00)
- (children 2
+ (children 1
(GraphicsLayer
- (position 100.00 100.00)
- (bounds 100.00 100.00)
- (drawsContent 1)
- (transform [0.71 0.71 0.00 0.00] [-0.71 0.71 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
- )
- (GraphicsLayer
- (bounds 784.00 784.00)
+ (offsetFromRenderer width=79 height=79)
+ (position 79.00 79.00)
+ (anchor -0.56 -0.56)
+ (bounds 142.00 142.00)
(drawsContent 1)
+ (transform [2.61 0.00 0.00 0.00] [0.00 2.61 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+ (children 1
+ (GraphicsLayer
+ (position 21.00 21.00)
+ (bounds 100.00 100.00)
+ (drawsContent 1)
+ (transform [0.71 0.71 0.00 0.00] [-0.71 0.71 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+ )
+ )
)
)
)
diff --git a/LayoutTests/platform/ios/svg/compositing/segment-removed-after-anchor-decomposited-layer-tree-expected.txt b/LayoutTests/platform/ios/svg/compositing/segment-removed-after-anchor-decomposited-layer-tree-expected.txt
new file mode 100644
index 000000000000..0f5a7082fe05
--- /dev/null
+++ b/LayoutTests/platform/ios/svg/compositing/segment-removed-after-anchor-decomposited-layer-tree-expected.txt
@@ -0,0 +1,91 @@
+ === Initial: middle painted into trailing segment ===
+(GraphicsLayer
+ (anchor 0.00 0.00)
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 600.00)
+ (contentsOpaque 1)
+ (children 1
+ (GraphicsLayer
+ (bounds 200.00 200.00)
+ (drawsContent 1)
+ (children 1
+ (GraphicsLayer
+ (bounds 200.00 200.00)
+ (children 1
+ (GraphicsLayer
+ (offsetFromRenderer width=10 height=10)
+ (position 10.00 10.00)
+ (anchor -0.06 -0.06)
+ (bounds 180.00 180.00)
+ (drawsContent 1)
+ (children 3
+ (GraphicsLayer
+ (anchor -0.08 -0.08)
+ (bounds 120.00 120.00)
+ (drawsContent 1)
+ )
+ (GraphicsLayer
+ (offsetFromRenderer width=10 height=10)
+ (bounds 180.00 180.00)
+ (drawsContent 1)
+ )
+ (GraphicsLayer
+ (position 60.00 60.00)
+ (anchor -0.58 -0.58)
+ (bounds 120.00 120.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
+=== After mutation: middle segment layer dropped ===
+(GraphicsLayer
+ (anchor 0.00 0.00)
+ (bounds 800.00 931.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 931.00)
+ (contentsOpaque 1)
+ (children 1
+ (GraphicsLayer
+ (bounds 200.00 200.00)
+ (drawsContent 1)
+ (children 1
+ (GraphicsLayer
+ (bounds 200.00 200.00)
+ (children 1
+ (GraphicsLayer
+ (offsetFromRenderer width=10 height=10)
+ (position 10.00 10.00)
+ (anchor -0.06 -0.06)
+ (bounds 180.00 180.00)
+ (drawsContent 1)
+ (children 1
+ (GraphicsLayer
+ (position 60.00 60.00)
+ (anchor -0.58 -0.58)
+ (bounds 120.00 120.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
+
diff --git a/LayoutTests/platform/ios/svg/compositing/transform-change-repainting-viewBox-repaintRects-expected.txt b/LayoutTests/platform/ios/svg/compositing/transform-change-repainting-viewBox-repaintRects-expected.txt
new file mode 100644
index 000000000000..596a7c7736a5
--- /dev/null
+++ b/LayoutTests/platform/ios/svg/compositing/transform-change-repainting-viewBox-repaintRects-expected.txt
@@ -0,0 +1,49 @@
+ (repaint rects
+ (rect 124 24 270 270)
+ (rect 124 24 270 270)
+ (rect 68 8 382 302)
+ (rect 8 8 502 302)
+)
+(GraphicsLayer
+ (anchor 0.00 0.00)
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 600.00)
+ (contentsOpaque 1)
+ (children 1
+ (GraphicsLayer
+ (position 8.00 8.00)
+ (bounds 502.00 302.00)
+ (drawsContent 1)
+ (children 1
+ (GraphicsLayer
+ (offsetFromRenderer width=1 height=1)
+ (position 1.00 1.00)
+ (bounds 500.00 300.00)
+ (children 1
+ (GraphicsLayer
+ (offsetFromRenderer width=-27.50 height=-27.50)
+ (position -27.50 -27.50)
+ (anchor 0.11 0.11)
+ (bounds 255.00 255.00)
+ (drawsContent 1)
+ (transform [1.50 0.00 0.00 0.00] [0.00 1.50 0.00 0.00] [0.00 0.00 1.00 0.00] [100.00 0.00 0.00 1.00])
+ (children 1
+ (GraphicsLayer
+ (position 37.50 37.50)
+ (bounds 180.00 180.00)
+ (drawsContent 1)
+ (transform [0.71 0.71 0.00 0.00] [-0.71 0.71 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
diff --git a/LayoutTests/platform/ios/svg/transforms/nested-svg-transform-attribute-creates-layer-expected.txt b/LayoutTests/platform/ios/svg/transforms/nested-svg-transform-attribute-creates-layer-expected.txt
new file mode 100644
index 000000000000..dba642154834
--- /dev/null
+++ b/LayoutTests/platform/ios/svg/transforms/nested-svg-transform-attribute-creates-layer-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x205
+ RenderBlock {HTML} at (0,0) size 800x204.50
+ RenderBody {BODY} at (0,0) size 800x204.50
+ RenderText {#text} at (0,0) size 0x0
+layer at (0,0) size 200x200
+ RenderSVGRoot {svg} at (0,0) size 200x200
+layer at (0,0) size 200x200
+ RenderSVGViewportContainer at (0,0) size 200x200
+layer at (0,0) size 200x200
+ RenderSVGViewportContainer {svg} at (0,0) size 200x200
+ RenderSVGRect {rect} at (60,90) size 80x20 [fill={[type=SOLID] [color=#008000]}] [x=60.00] [y=90.00] [width=80.00] [height=20.00]
diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/repaint/svg-outline-repaint-on-hover-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/repaint/svg-outline-repaint-on-hover-expected.txt
new file mode 100644
index 000000000000..9826a460f4b0
--- /dev/null
+++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/repaint/svg-outline-repaint-on-hover-expected.txt
@@ -0,0 +1,17 @@
+ SVG border box: 100x100 at (50,50)
+
+Repaint rects on hover (outline added):
+(repaint rects
+ (rect 50 50 100 100)
+ (rect 0 0 800 204)
+ (rect 35 35 130 130)
+)
+
+Repaint rects on un-hover (outline removed):
+(repaint rects
+ (rect 35 35 130 130)
+ (rect 50 50 100 100)
+ (rect 0 0 800 204)
+ (rect 35 35 130 130)
+)
+
diff --git a/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private-expected.txt b/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private-expected.txt
new file mode 100644
index 000000000000..df3122fe29ba
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private-expected.txt
@@ -0,0 +1,16 @@
+Tests that a reverse index cursor doesn't use-after-free when a record is deleted whose index key is the next-higher value from the cursor's current position.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+PASS cursorKeys.length is 3
+PASS cursorKeys[0] is 30
+PASS cursorKeys[1] is 20
+PASS cursorKeys[2] is 10
+Transaction completed successfully.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private.html b/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private.html
new file mode 100644
index 000000000000..6ea56d78bdeb
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race-expected.txt b/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race-expected.txt
new file mode 100644
index 000000000000..13e6354090c4
--- /dev/null
+++ b/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race-expected.txt
@@ -0,0 +1,3 @@
+This test passes if it does not crash when toggling BiquadFilterNode.type while the channel count changes on the audio thread.
+
+PASS: did not crash.
diff --git a/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race.html b/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race.html
new file mode 100644
index 000000000000..d1af2217d775
--- /dev/null
+++ b/LayoutTests/webaudio/biquadfilternode-set-type-channel-count-race.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+This test passes if it does not crash when toggling BiquadFilterNode.type while the channel count changes on the audio thread.
+
+
+
diff --git a/LayoutTests/workers/weblock-manager-query-crash-expected.txt b/LayoutTests/workers/weblock-manager-query-crash-expected.txt
new file mode 100644
index 000000000000..730ebf66a0da
--- /dev/null
+++ b/LayoutTests/workers/weblock-manager-query-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash.
diff --git a/LayoutTests/workers/weblock-manager-query-crash.html b/LayoutTests/workers/weblock-manager-query-crash.html
new file mode 100644
index 000000000000..de3aa909f638
--- /dev/null
+++ b/LayoutTests/workers/weblock-manager-query-crash.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+This test passes if it doesn't crash.
+
+
diff --git a/Source/JavaScriptCore/builtins/TypedArrayConstructor.js b/Source/JavaScriptCore/builtins/TypedArrayConstructor.js
index 785388293703..8e757caae907 100644
--- a/Source/JavaScriptCore/builtins/TypedArrayConstructor.js
+++ b/Source/JavaScriptCore/builtins/TypedArrayConstructor.js
@@ -109,11 +109,17 @@ function from(items /* [ , mapfn [ , thisArg ] ] */)
@throwTypeError("TypedArray.from constructed typed array of insufficient length");
for (var k = 0; k < arrayLikeLength; k++) {
+ if (@isTypedArrayView(arrayLike) && (@isDetached(arrayLike) || k >= @typedArrayLength(arrayLike)))
+ break;
var value = arrayLike[k];
if (mapFn === @undefined)
result[k] = value;
- else
- result[k] = thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k);
+ else {
+ var mapped = thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k);
+ if (@isTypedArrayView(result) && (k >= @typedArrayLength(result) || @isDetached(result)))
+ break;
+ result[k] = mapped;
+ }
}
return result;
diff --git a/Source/JavaScriptCore/bytecode/Repatch.cpp b/Source/JavaScriptCore/bytecode/Repatch.cpp
index 081e1f33a76e..fd98ba46efc3 100644
--- a/Source/JavaScriptCore/bytecode/Repatch.cpp
+++ b/Source/JavaScriptCore/bytecode/Repatch.cpp
@@ -796,6 +796,7 @@ void repatchGetBy(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue ba
// Mainly used to transition from megamorphic case to generic case.
void repatchGetBySlowPathCall(CodeBlock* codeBlock, PropertyInlineCache& propertyCache, GetByKind kind)
{
+ ConcurrentJSLocker locker(codeBlock->m_lock);
resetGetBy(codeBlock, propertyCache, kind);
repatchSlowPathCall(codeBlock, propertyCache, appropriateGetByGaveUpFunction(kind));
}
@@ -1000,6 +1001,7 @@ static CodePtr NODELETE appropriatePutByGaveUpFunction(PutByKin
// Mainly used to transition from megamorphic case to generic case.
void repatchPutBySlowPathCall(CodeBlock* codeBlock, PropertyInlineCache& propertyCache, PutByKind kind)
{
+ ConcurrentJSLocker locker(codeBlock->m_lock);
resetPutBy(codeBlock, propertyCache, kind);
repatchSlowPathCall(codeBlock, propertyCache, appropriatePutByGaveUpFunction(kind));
}
@@ -1631,6 +1633,7 @@ inline CodePtr NODELETE appropriateInByGaveUpFunction(InByKind
// Mainly used to transition from megamorphic case to generic case.
void repatchInBySlowPathCall(CodeBlock* codeBlock, PropertyInlineCache& propertyCache, InByKind kind)
{
+ ConcurrentJSLocker locker(codeBlock->m_lock);
resetInBy(codeBlock, propertyCache, kind);
repatchSlowPathCall(codeBlock, propertyCache, appropriateInByGaveUpFunction(kind));
}
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index c4a337809bb3..2acbc4bfd89c 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -3860,7 +3860,12 @@ bool AbstractInterpreter::executeEffects(unsigned clobberLimi
break;
}
- setForNode(node, m_vm.cellButterflyStructure(CopyOnWriteArrayWithContiguous));
+ {
+ RegisteredStructureSet structureSet;
+ structureSet.add(m_graph.registerStructure(m_vm.cellButterflyStructure(CopyOnWriteArrayWithContiguous)));
+ structureSet.add(m_graph.registerStructure(m_vm.cellButterflyOnlyAtomStringsStructure.get()));
+ setForNode(node, structureSet);
+ }
break;
case NewArrayBuffer:
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
index 509c0ccf40d1..b90a0b9649cf 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
@@ -604,7 +604,7 @@ class ArgumentsEliminationPhase : public Phase {
return interfere;
};
- auto removeViaKill = [&](BasicBlock* block, unsigned nodeIndex, Node* candidate) {
+ auto removeViaKill = [&](BasicBlock* block, const unsigned nodeIndex, Node* candidate) {
if (!m_candidates.contains(candidate))
return;
@@ -660,21 +660,17 @@ class ArgumentsEliminationPhase : public Phase {
}
// This loop considers all nodes up to the nodeIndex, excluding the nodeIndex.
+ // scanIndex is a working copy so each inline call frame independently
+ // scans the full [0, nodeIndex) range.
//
- // Note: nodeIndex here has a double meaning. Before entering this
- // while loop, it refers to the remaining number of nodes that have
- // yet to be processed. Inside the loop, it refers to the index
- // of the current node to process (after we decrement it).
- //
- // If the remaining number of nodes is 0, we should not decrement nodeIndex.
- // Hence, we must only decrement nodeIndex inside the while loop instead of
- // in its condition statement. Note that this while loop is embedded in an
- // outer for loop. If we decrement nodeIndex in the condition statement, a
- // nodeIndex of 0 will become UINT_MAX, and the outer loop will wrongly
- // treat this as there being UINT_MAX remaining nodes to process.
- while (nodeIndex) {
- --nodeIndex;
- Node* node = block->at(nodeIndex);
+ // If the remaining number of nodes is 0, we should not decrement
+ // scanIndex. Hence, we must only decrement it inside the while loop
+ // instead of in its condition statement; otherwise a scanIndex of 0 would
+ // become UINT_MAX.
+ unsigned scanIndex = nodeIndex;
+ while (scanIndex) {
+ --scanIndex;
+ Node* node = block->at(scanIndex);
if (node == candidate)
break;
@@ -693,7 +689,7 @@ class ArgumentsEliminationPhase : public Phase {
NoOpClobberize());
if (found) {
- dataLogLnIf(DFGArgumentsEliminationPhaseInternal::verbose, "eliminating candidate: ", candidate, " because it is clobbered by ", block->at(nodeIndex));
+ dataLogLnIf(DFGArgumentsEliminationPhaseInternal::verbose, "eliminating candidate: ", candidate, " because it is clobbered by ", block->at(scanIndex));
transitivelyRemoveCandidate(candidate);
return;
}
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 9c169d6f3ef4..9acd38e1d10e 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -1540,6 +1540,10 @@ ObjectPropertyConditionSet Graph::tryEnsureAbsence(JSGlobalObject* globalObject,
return ObjectPropertyConditionSet::invalid();
auto isAbsenceCacheable = [&](Structure* structure) {
+ // Absences cannot be cached on any dictionaries, including CachedDictionaryKind, because
+ // new properties can be added without structure transitions.
+ if (structure->isDictionary())
+ return false;
if (structure->typeInfo().overridesGetOwnPropertySlot())
return false;
if (!structure->propertyAccessesAreCacheable())
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index cac3bb0681e3..8c19646ba8fb 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -847,6 +847,40 @@ ALWAYS_INLINE EncodedJSValue getByValCellInt(JSGlobalObject* globalObject, VM& v
return JSValue::encode(JSValue(base).get(globalObject, static_cast(index)));
}
+ALWAYS_INLINE EncodedJSValue getByValArrayStorageInt(JSGlobalObject* globalObject, VM& vm, JSObject* base, int32_t index)
+{
+ ASSERT(hasAnyArrayStorage(base->indexingType()));
+ if (index >= 0) [[likely]] {
+ unsigned i = static_cast(index);
+ ArrayStorage* storage = base->butterfly()->arrayStorage();
+ SparseArrayValueMap* map = storage->m_sparseMap.get();
+ // Only the standard ArrayStorage layout is handled here: indices < vectorLength live in the
+ // vector, overflow indices live in a non-sparse-mode map with no per-entry attributes. When the
+ // map is in sparse mode (frozen/sealed/read-only/accessor arrays), values for in-vector indices
+ // may have migrated into the map and entries carry attributes, so defer to the generic path.
+ if (!map || !map->sparseMode()) [[likely]] {
+ if (i < storage->vectorLength()) {
+ JSValue value = storage->m_vector[i].get();
+ if (value)
+ return JSValue::encode(value);
+ } else if (map) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->notFound()) {
+ if (it->value.attributes()) [[unlikely]] // accessor / special: needs the full slot path.
+ return JSValue::encode(JSValue(base).get(globalObject, i));
+ return JSValue::encode(it->value.getNonSparseMode());
+ }
+ }
+
+ // Missing own indexed property: undefined unless the prototype chain can intercept it.
+ if (!base->structure()->holesMustForwardToPrototype(base))
+ return JSValue::encode(jsUndefined());
+ }
+ }
+ // Negative index, sparse/dictionary mode, accessor entry, or intercepting prototype chain.
+ return getByValCellInt(globalObject, vm, base, index);
+}
+
JSC_DEFINE_JIT_OPERATION(operationGetByValObjectInt, EncodedJSValue, (JSGlobalObject* globalObject, JSObject* base, int32_t index))
{
VM& vm = globalObject->vm();
@@ -857,6 +891,16 @@ JSC_DEFINE_JIT_OPERATION(operationGetByValObjectInt, EncodedJSValue, (JSGlobalOb
OPERATION_RETURN(scope, getByValCellInt(globalObject, vm, base, index));
}
+JSC_DEFINE_JIT_OPERATION(operationGetByValArrayStorageInt, EncodedJSValue, (JSGlobalObject* globalObject, JSObject* base, int32_t index))
+{
+ VM& vm = globalObject->vm();
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ OPERATION_RETURN(scope, getByValArrayStorageInt(globalObject, vm, base, index));
+}
+
JSC_DEFINE_JIT_OPERATION(operationGetByValStringInt, EncodedJSValue, (JSGlobalObject* globalObject, JSString* base, int32_t index))
{
VM& vm = globalObject->vm();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 686fcc6db4c0..d750fef9c82d 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -117,6 +117,7 @@ JSC_DECLARE_JIT_OPERATION(operationArithTrunc, EncodedJSValue, (JSGlobalObject*,
JSC_DECLARE_NOEXCEPT_JIT_OPERATION(operationArithMinMultipleDouble, double, (const double* buffer, unsigned elementCount));
JSC_DECLARE_NOEXCEPT_JIT_OPERATION(operationArithMaxMultipleDouble, double, (const double* buffer, unsigned elementCount));
JSC_DECLARE_JIT_OPERATION(operationGetByValObjectInt, EncodedJSValue, (JSGlobalObject*, JSObject*, int32_t));
+JSC_DECLARE_JIT_OPERATION(operationGetByValArrayStorageInt, EncodedJSValue, (JSGlobalObject*, JSObject*, int32_t));
JSC_DECLARE_JIT_OPERATION(operationGetByValStringInt, EncodedJSValue, (JSGlobalObject*, JSString*, int32_t));
JSC_DECLARE_JIT_OPERATION(operationGetByValObjectString, EncodedJSValue, (JSGlobalObject*, JSCell*, JSCell* string));
JSC_DECLARE_JIT_OPERATION(operationGetByValObjectSymbol, EncodedJSValue, (JSGlobalObject*, JSCell*, JSCell* symbol));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index abb1f2a38960..06c06e28c75b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2112,7 +2112,7 @@ void SpeculativeJIT::compileGetByVal(Node* node, const ScopedLambda
class StoreBarrierInsertionPhase : public Phase {
public:
@@ -369,9 +371,20 @@ class StoreBarrierInsertionPhase : public Phase {
break;
}
- case MultiPutByOffset:
+ case MultiPutByOffset: {
+ // This node may cause a transition before performing a store if it reallocates
+ // storage. This is different from the usual assumption in this phase a node's fast
+ // path either does GC or performs a store, but not both within the same node (a
+ // slow path call to an operation always performs its own barrier). In this special
+ // case, bump the epoch before considering the barrier.
+ if (m_node->multiPutByOffsetData().reallocatesStorage())
+ m_currentEpoch.bump();
+ considerBarrier(m_node->child1());
+ break;
+ }
+
case MultiDeleteByOffset: {
- // These nodes may cause transition too.
+ // This node may cause a transition but does not GC.
considerBarrier(m_node->child1());
break;
}
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 5bb87453fe4a..0f8ee575a4e9 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -6746,7 +6746,7 @@ IGNORE_CLANG_WARNINGS_END
m_out.appendTo(slowCase, continuation);
ValueFromBlock slowResult = m_out.anchor(
- vmCall(Int64, operationGetByValObjectInt, weakPointer(globalObject), base, index));
+ vmCall(Int64, operationGetByValArrayStorageInt, weakPointer(globalObject), base, index));
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js
index 87e20d1d2d75..36aae68bf3fd 100644
--- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js
+++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js
@@ -842,6 +842,29 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase
break;
}
+ if (shouldBreak)
+ break;
+
+ let privateMethods = InjectedScriptHost.getOwnPrivatePropertyMethods(o, isOwnProperty);
+ for (let i = 0; i < privateMethods.length; ++i) {
+ let privateMethod = privateMethods[i];
+ let descriptor = @createObjectWithoutPrototype();
+ descriptor.name = privateMethod.name;
+ if (@Object.@hasOwn(privateMethod, "value"))
+ descriptor.value = privateMethod.value;
+ if (@Object.@hasOwn(privateMethod, "get"))
+ descriptor.get = privateMethod.get;
+ if (@Object.@hasOwn(privateMethod, "set"))
+ descriptor.set = privateMethod.set;
+ if (isOwnProperty)
+ descriptor.isOwn = true;
+ descriptor.isPrivate = true;
+ let result = processDescriptor(descriptor, isOwnProperty);
+ shouldBreak = result === InjectedScript.PropertyFetchAction.Stop;
+ if (shouldBreak)
+ break;
+ }
+
if (shouldBreak)
break;
diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
index ba1287ef8556..ee1c95accc67 100644
--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
@@ -46,10 +46,12 @@
#include "JSCInlines.h"
#include "JSFinalizationRegistry.h"
#include "JSInjectedScriptHostPrototype.h"
+#include "JSLexicalEnvironment.h"
#include "JSMap.h"
#include "JSMapIterator.h"
#include "JSPromise.h"
#include "JSPromisePrototype.h"
+#include "JSScope.h"
#include "JSSet.h"
#include "JSSetIterator.h"
#include "JSStringIterator.h"
@@ -66,6 +68,7 @@
#include "ScopedArguments.h"
#include "SourceCode.h"
#include "StructureCreateInlines.h"
+#include "SymbolTable.h"
#include
#include
#include
@@ -305,7 +308,7 @@ static JSObject* constructInternalProperty(JSGlobalObject* globalObject, const S
JSValue JSInjectedScriptHost::getOwnPrivatePropertySymbols(JSGlobalObject* globalObject, CallFrame* callFrame)
{
- if (callFrame->argumentCount() < 1)
+ if (callFrame->argumentCount() < 1) [[unlikely]]
return jsUndefined();
VM& vm = globalObject->vm();
@@ -316,7 +319,7 @@ JSValue JSInjectedScriptHost::getOwnPrivatePropertySymbols(JSGlobalObject* globa
RETURN_IF_EXCEPTION(scope, JSValue());
JSObject* object = dynamicDowncast(value);
- if (!object)
+ if (!object) [[unlikely]]
return result;
unsigned index = 0;
@@ -336,6 +339,176 @@ JSValue JSInjectedScriptHost::getOwnPrivatePropertySymbols(JSGlobalObject* globa
return result;
}
+JSValue JSInjectedScriptHost::getOwnPrivatePropertyMethods(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ if (callFrame->argumentCount() < 1) [[unlikely]]
+ return jsUndefined();
+
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue value = callFrame->uncheckedArgument(0);
+
+ // Static private methods/accessors are not accessible through the prototype chain, so only
+ // surface them when the class constructor or its `prototype` is the object being inspected.
+ bool isDirectlyInspectingObject = callFrame->argument(1).toBoolean(globalObject);
+
+ JSArray* result = constructEmptyArray(globalObject, nullptr);
+ RETURN_IF_EXCEPTION(scope, JSValue());
+
+ JSObject* object = dynamicDowncast(value);
+ if (!object) [[unlikely]]
+ return result;
+
+ Identifier nameIdentifier = Identifier::fromString(vm, "name"_s);
+ Identifier valueIdentifier = Identifier::fromString(vm, "value"_s);
+ Identifier getIdentifier = Identifier::fromString(vm, "get"_s);
+ Identifier setIdentifier = Identifier::fromString(vm, "set"_s);
+
+ enum class IncludeStatic : bool { No, Yes };
+
+ unsigned index = 0;
+ auto appendMembers = [&](JSScope* classScope, IncludeStatic includeStatic) {
+ SymbolTable* symbolTable = classScope->symbolTable();
+ if (!symbolTable)
+ return;
+
+ Vector, PrivateNameEntry>> members;
+ {
+ ConcurrentJSLocker locker(symbolTable->m_lock);
+ if (!symbolTable->hasPrivateNames())
+ return;
+ auto privateNames = symbolTable->privateNames();
+ for (auto end = privateNames.end(), iter = privateNames.begin(); iter != end; ++iter) {
+ const PrivateNameEntry& entry = iter->value;
+ if (!entry.isPrivateMethodOrAccessor() || entry.isStatic() != (includeStatic == IncludeStatic::Yes))
+ continue;
+ members.append({ iter->key.get(), entry });
+ }
+ }
+
+ std::sort(members.begin(), members.end(), [](const auto& a, const auto& b) {
+ return codePointCompareLessThan(StringView(a.first.get()), StringView(b.first.get()));
+ });
+
+ for (const auto& [name, entry] : members) {
+ Identifier memberIdentifier = Identifier::fromUid(vm, name.get());
+ JSValue memberValue = classScope->get(globalObject, memberIdentifier);
+ RETURN_IF_EXCEPTION(scope, void());
+
+ JSObject* descriptor = constructEmptyObject(globalObject);
+ descriptor->putDirect(vm, nameIdentifier, jsString(vm, memberIdentifier.string()));
+ if (entry.isMethod())
+ descriptor->putDirect(vm, valueIdentifier, memberValue);
+ else {
+ JSValue getter = jsUndefined();
+ JSValue setter = jsUndefined();
+ if (JSObject* holder = dynamicDowncast(memberValue)) {
+ getter = holder->get(globalObject, vm.propertyNames->builtinNames().getPrivateName());
+ RETURN_IF_EXCEPTION(scope, void());
+ setter = holder->get(globalObject, vm.propertyNames->builtinNames().setPrivateName());
+ RETURN_IF_EXCEPTION(scope, void());
+ }
+ descriptor->putDirect(vm, getIdentifier, getter);
+ descriptor->putDirect(vm, setIdentifier, setter);
+ }
+
+ result->putDirectIndex(globalObject, index++, descriptor);
+ RETURN_IF_EXCEPTION(scope, void());
+ }
+ };
+
+ auto scopeHasPrivateMethod = [&](SymbolTable* symbolTable, IncludeStatic includeStatic) -> bool {
+ ConcurrentJSLocker locker(symbolTable->m_lock);
+ if (!symbolTable->hasPrivateNames())
+ return false;
+ auto privateNames = symbolTable->privateNames();
+ for (auto end = privateNames.end(), iter = privateNames.begin(); iter != end; ++iter) {
+ if (iter->value.isPrivateMethodOrAccessor() && iter->value.isStatic() == (includeStatic == IncludeStatic::Yes))
+ return true;
+ }
+ return false;
+ };
+
+ // Static private methods/accessors live in the class scope behind a "brand" that is the class itself.
+ auto appendStaticPrivateMethods = [&](JSFunction* classConstructor) {
+ for (JSScope* classScope = classConstructor->scope(); classScope; classScope = classScope->next()) {
+ SymbolTable* symbolTable = classScope->symbolTable();
+ if (!symbolTable || !scopeHasPrivateMethod(symbolTable, IncludeStatic::Yes))
+ continue;
+
+ JSValue classBrand = classScope->get(globalObject, vm.propertyNames->builtinNames().privateClassBrandPrivateName());
+ RETURN_IF_EXCEPTION(scope, void());
+ if (classBrand != classConstructor)
+ continue;
+
+ appendMembers(classScope, IncludeStatic::Yes);
+ RETURN_IF_EXCEPTION(scope, void());
+ break;
+ }
+ };
+
+ if (isDirectlyInspectingObject) {
+ // When inspecting the class constructor directly.
+ if (JSFunction* function = dynamicDowncast(object)) {
+ appendStaticPrivateMethods(function);
+ RETURN_IF_EXCEPTION(scope, { });
+ return result;
+ }
+
+ // When inspecting the class `prototype`, either directly or via the instance.
+ JSValue classConstructorValue = object->getDirect(vm, vm.propertyNames->constructor);
+ if (JSFunction* classConstructor = classConstructorValue ? dynamicDowncast(classConstructorValue) : nullptr) {
+ JSValue classConstructorPrototype = classConstructor->get(globalObject, vm.propertyNames->prototype);
+ RETURN_IF_EXCEPTION(scope, { });
+ if (classConstructorPrototype == object) {
+ appendStaticPrivateMethods(classConstructor);
+ RETURN_IF_EXCEPTION(scope, { });
+ }
+ }
+ }
+
+ // Instance private methods/accessors live in the class scope behind a structural brand carried
+ // by every instance (including instances of superclasses, via `super()`). Walk the prototype
+ // chain to reach each class scope, keeping only those whose brand this object actually carries.
+ MarkedVector seenSymbolTables;
+ MarkedVector instanceScopes;
+ for (JSValue prototype = object->getPrototypeDirect(); prototype.isObject(); prototype = asObject(prototype)->getPrototypeDirect()) {
+ JSValue constructorValue = asObject(prototype)->getDirect(vm, vm.propertyNames->constructor);
+ if (!constructorValue)
+ continue;
+ JSFunction* constructorFunction = dynamicDowncast(constructorValue);
+ if (!constructorFunction)
+ continue;
+
+ for (JSScope* classScope = constructorFunction->scope(); classScope; classScope = classScope->next()) {
+ SymbolTable* symbolTable = classScope->symbolTable();
+ if (!symbolTable || std::find(seenSymbolTables.begin(), seenSymbolTables.end(), symbolTable) != seenSymbolTables.end())
+ continue;
+
+ seenSymbolTables.append(symbolTable);
+
+ if (!scopeHasPrivateMethod(symbolTable, IncludeStatic::No))
+ continue;
+
+ JSValue instanceBrand = classScope->get(globalObject, vm.propertyNames->builtinNames().privateBrandPrivateName());
+ RETURN_IF_EXCEPTION(scope, { });
+ if (!instanceBrand.isSymbol())
+ continue;
+
+ if (object->hasPrivateBrand(globalObject, instanceBrand))
+ instanceScopes.append(classScope);
+ }
+ }
+
+ // Emit superclass members before subclass members, matching how private fields are ordered.
+ for (size_t i = instanceScopes.size(); i--;) {
+ appendMembers(instanceScopes[i], IncludeStatic::No);
+ RETURN_IF_EXCEPTION(scope, { });
+ }
+
+ return result;
+}
+
JSValue JSInjectedScriptHost::getInternalProperties(JSGlobalObject* globalObject, CallFrame* callFrame)
{
if (callFrame->argumentCount() < 1)
diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h
index f47b40dbb850..a163a627c889 100644
--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h
+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h
@@ -71,6 +71,7 @@ class JSInjectedScriptHost final : public JSC::JSNonFinalObject {
JSC::JSValue subtype(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC::JSValue functionDetails(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC::JSValue getOwnPrivatePropertySymbols(JSC::JSGlobalObject*, JSC::CallFrame*);
+ JSC::JSValue getOwnPrivatePropertyMethods(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC::JSValue getInternalProperties(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC::JSValue NODELETE proxyTargetValue(JSC::CallFrame*);
JSC::JSValue weakRefTargetValue(JSC::JSGlobalObject*, JSC::CallFrame*);
diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp
index bf4f64d0a6da..5b934f9a3fb1 100644
--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp
+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp
@@ -37,6 +37,7 @@ using namespace JSC;
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionSubtype);
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionFunctionDetails);
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertySymbols);
+static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertyMethods);
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetInternalProperties);
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionInternalConstructorName);
static JSC_DECLARE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection);
@@ -65,6 +66,7 @@ void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globa
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("subtype"_s, jsInjectedScriptHostPrototypeFunctionSubtype, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("functionDetails"_s, jsInjectedScriptHostPrototypeFunctionFunctionDetails, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("getOwnPrivatePropertySymbols"_s, jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertySymbols, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("getOwnPrivatePropertyMethods"_s, jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertyMethods, static_cast(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Private);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("getInternalProperties"_s, jsInjectedScriptHostPrototypeFunctionGetInternalProperties, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("internalConstructorName"_s, jsInjectedScriptHostPrototypeFunctionInternalConstructorName, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("isHTMLAllCollection"_s, jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection, static_cast(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private);
@@ -319,6 +321,19 @@ JSC_DEFINE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePrope
return JSValue::encode(castedThis->getOwnPrivatePropertySymbols(globalObject, callFrame));
}
+JSC_DEFINE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertyMethods, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue thisValue = callFrame->thisValue();
+ JSInjectedScriptHost* castedThis = dynamicDowncast(thisValue);
+ if (!castedThis)
+ return throwVMTypeError(globalObject, scope);
+
+ return JSValue::encode(castedThis->getOwnPrivatePropertyMethods(globalObject, callFrame));
+}
+
JSC_DEFINE_HOST_FUNCTION(jsInjectedScriptHostPrototypeFunctionGetInternalProperties, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
diff --git a/Source/JavaScriptCore/runtime/JSObjectInlines.h b/Source/JavaScriptCore/runtime/JSObjectInlines.h
index 915538b10146..86e5face3845 100644
--- a/Source/JavaScriptCore/runtime/JSObjectInlines.h
+++ b/Source/JavaScriptCore/runtime/JSObjectInlines.h
@@ -919,7 +919,7 @@ inline bool JSObject::getPrivateField(JSGlobalObject* globalObject, PropertyName
ASSERT(!slot.isVMInquiry());
if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
throwException(globalObject, scope, createInvalidPrivateNameError(globalObject));
- RELEASE_AND_RETURN(scope, false);
+ return false;
}
EXCEPTION_ASSERT(!scope.exception());
RELEASE_AND_RETURN(scope, true);
@@ -932,7 +932,7 @@ inline void JSObject::setPrivateField(JSGlobalObject* globalObject, PropertyName
PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
throwException(globalObject, scope, createInvalidPrivateNameError(globalObject));
- RELEASE_AND_RETURN(scope, void());
+ return;
}
EXCEPTION_ASSERT(!scope.exception());
@@ -944,10 +944,16 @@ inline void JSObject::definePrivateField(JSGlobalObject* globalObject, PropertyN
{
VM& vm = getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (type() == WebAssemblyGCObjectType) {
+ throwTypeError(globalObject, scope, "Cannot define private field on a WebAssembly GC object"_s);
+ return;
+ }
+
PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
if (JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
throwException(globalObject, scope, createRedefinedPrivateNameError(globalObject));
- RELEASE_AND_RETURN(scope, void());
+ return;
}
EXCEPTION_ASSERT(!scope.exception());
@@ -1008,10 +1014,15 @@ inline void JSObject::setPrivateBrand(JSGlobalObject* globalObject, JSValue bran
Structure* structure = this->structure();
if (structure->isBrandedStructure() && uncheckedDowncast(structure)->checkBrand(asSymbol(brand))) {
throwException(globalObject, scope, createReinstallPrivateMethodError(globalObject));
- RELEASE_AND_RETURN(scope, void());
+ return;
}
EXCEPTION_ASSERT(!scope.exception());
+ if (type() == WebAssemblyGCObjectType) {
+ throwTypeError(globalObject, scope, "Cannot add private method to a WebAssembly GC object"_s);
+ return;
+ }
+
scope.release();
DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure);
diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h
index a7a9275b8801..dba9d6e9411b 100644
--- a/Source/JavaScriptCore/runtime/OptionsList.h
+++ b/Source/JavaScriptCore/runtime/OptionsList.h
@@ -339,6 +339,7 @@ bool hasCapacityToUseLargeGigacage();
v(Unsigned, maximumBinaryStringSwitchCaseLength, 50, Normal, nullptr) \
v(Unsigned, maximumBinaryStringSwitchTotalLength, 2000, Normal, nullptr) \
v(Unsigned, maximumRegExpTestInlineCodesize, 500, Normal, "Maximum code size in bytes for inlined RegExp.test JIT code."_s) \
+ v(Unsigned, maximumRegExpJITCodeSize, 16 * MB, Normal, "Maximum generated code size in bytes for RegExp JIT compilation before falling back to the interpreter."_s) \
\
v(Unsigned, wasmInliningMaximumDepth, 7, Normal, "Maximum inlining depth to consider inlining a wasm function."_s) \
v(Unsigned, wasmInliningMaximumWasmCalleeSize, 500, Normal, "Maximum wasm size in bytes to consider inlining a wasm function."_s) \
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 9fcfeb3702a1..bd9e01f437e4 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -245,15 +245,16 @@ Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, co
{
bool hasStaticNonEnumerableProperty = m_classInfo->hasStaticPropertyWithAnyOfAttributes(static_cast(PropertyAttribute::DontEnum));
bool hasStaticNonConfigurableProperty = m_classInfo->hasStaticPropertyWithAnyOfAttributes(static_cast(PropertyAttribute::DontDelete));
+ bool isArrayStorage = hasAnyArrayStorage(indexingType);
setDictionaryKind(NoneDictionaryKind);
setIsPinnedPropertyTable(false);
setHasAnyKindOfGetterSetterProperties(m_classInfo->hasStaticPropertyWithAnyOfAttributes(static_cast(PropertyAttribute::AccessorOrCustomAccessorOrValue)));
setHasReadOnlyOrGetterSetterPropertiesExcludingProto(hasAnyKindOfGetterSetterProperties() || m_classInfo->hasStaticPropertyWithAnyOfAttributes(static_cast(PropertyAttribute::ReadOnly)));
- setHasNonEnumerableProperties(hasStaticNonEnumerableProperty || typeInfo.overridesGetOwnPropertySlot());
+ setHasNonEnumerableProperties(hasStaticNonEnumerableProperty || typeInfo.overridesGetOwnPropertySlot() || isArrayStorage);
setHasSpecialProperties(false);
- setHasNonConfigurableProperties(hasStaticNonConfigurableProperty || typeInfo.overridesGetOwnPropertySlot());
- setHasNonConfigurableReadOnlyOrGetterSetterProperties(hasStaticNonConfigurableProperty || (typeInfo.overridesGetOwnPropertySlot() && typeInfo.type() != ArrayType));
+ setHasNonConfigurableProperties(hasStaticNonConfigurableProperty || typeInfo.overridesGetOwnPropertySlot() || isArrayStorage);
+ setHasNonConfigurableReadOnlyOrGetterSetterProperties(hasStaticNonConfigurableProperty || (typeInfo.overridesGetOwnPropertySlot() && typeInfo.type() != ArrayType) || isArrayStorage);
setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
setIsQuickPropertyAccessAllowedForEnumeration(true);
setTransitionPropertyAttributes(0);
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 85df7c709c6c..de5071e12692 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -347,6 +347,8 @@ class Structure : public JSCell {
bool propertyAccessesAreCacheableForAbsence()
{
+ // FIXME: dictionaries cannot be cached for absence, so check for dictionaries here instead
+ // of at all call sites.
return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence();
}
diff --git a/Source/JavaScriptCore/wasm/WasmCallee.cpp b/Source/JavaScriptCore/wasm/WasmCallee.cpp
index 778b440e9a1e..7a6a8ade547e 100644
--- a/Source/JavaScriptCore/wasm/WasmCallee.cpp
+++ b/Source/JavaScriptCore/wasm/WasmCallee.cpp
@@ -585,7 +585,6 @@ unsigned OptimizingJITCallee::computeCodeHashImpl() const
BBQCallee::~BBQCallee()
{
if (Options::freeRetiredWasmCode() && m_osrEntryCallee) {
- ASSERT(m_osrEntryCallee->hasOneRef());
m_osrEntryCallee->reportToVMsForDestruction();
}
}
diff --git a/Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp b/Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp
index 4de1d1668868..db99bffd98e1 100644
--- a/Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp
+++ b/Source/JavaScriptCore/wasm/WasmCalleeGroup.cpp
@@ -346,14 +346,9 @@ void CalleeGroup::updateCallsitesToCallUs(const AbstractLocker& locker, CodeLoca
// This is necessary since Callees are released under `Heap::stopThePeriphery()`, but that only stops JS compiler
// threads and not wasm ones. So a weakly held BBQCallee and its OMGOSREntryCallee could die between the time we
- // collect the callsites and when we actually repatch its callsites. Since BBQCallee owns OMGOSREntryCallee,
- // keeping BBQCallee alive is enough to ensure that both are alive for the required duration.
- //
- // There is however an edge case here - it can happen that a BBQCallee has been freed but its OMGOSREntryCallee
- // has been added to the pending-destruction set and not yet free'd. This means that m_osrEntryCallees will still
- // hold a weak ref to it. In this scenario, BBQCallee won't be kept alive since it does not exist so we manually
- // have to keep the OMGOSREntryCallee alive separately. This should only be done in this scenario else we will
- // end up with multiple owners for OMGOSREntryCallee.
+ // collect the callsites and when we actually repatch its callsites. Additionally, after a re-tier (where a fresh
+ // BBQCallee replaces a retired one), m_osrEntryCallees may hold a stale weak ref to an OMGOSREntryCallee not
+ // owned by the current BBQCallee, so we always keep it alive unconditionally.
// FIXME: These inline capacities were picked semi-randomly. We should figure out if there's a better number.
#if ENABLE(WEBASSEMBLY_BBQJIT)
@@ -384,8 +379,6 @@ void CalleeGroup::updateCallsitesToCallUs(const AbstractLocker& locker, CodeLoca
if (!tuple)
return;
- bool bbqCalleeKeptAlive = false;
- UNUSED_VARIABLE(bbqCalleeKeptAlive);
#if ENABLE(WEBASSEMBLY_BBQJIT)
// This callee could be weak but we still need to update it since it could call our BBQ callee
// that we're going to want to destroy.
@@ -398,25 +391,15 @@ void CalleeGroup::updateCallsitesToCallUs(const AbstractLocker& locker, CodeLoca
collectCallsites(bbqCallee.get());
ASSERT(!bbqCallee->osrEntryCallee() || m_osrEntryCallees.find(callerIndex) != m_osrEntryCallees.end());
keepAliveBBQCallees.append(bbqCallee.releaseNonNull());
- bbqCalleeKeptAlive = true;
}
#endif
#if ENABLE(WEBASSEMBLY_OMGJIT)
collectCallsites(tuple->m_omgCallee.get());
if (auto iter = m_osrEntryCallees.find(callerIndex); iter != m_osrEntryCallees.end()) {
if (RefPtr callee = iter->value.get()) {
+ // Since there is a OMGOSREntryCallee, we need to collect all the callsites there and also keep it alive until we patch it.
collectCallsites(callee.get());
- // If we track the OMGOSREntryCallee as a callsite there are 2 possibilities -
- // 1. The BBQCallee is already being tracked - in this case we don't have to
- // track the OMGOSREntryCallee since the BBQCallee owns it and keeping the
- // BBQCallee alive is good enough to keep the OMGOSREntryCallee alive. Also,
- // OMGOSREntryCallee is only supposed to be owned by BBQCallee
- // 2. The BBQCallee is not tracked - This happens if the BBQCallee is already
- // released but the OMGOSREntryCallee is still alive. In this case there is
- // no other strong reference to OMGOSREntryCallee so we have to keep it
- // alive here.
- if (!bbqCalleeKeptAlive)
- keepAliveOSREntryCallees.append(callee.releaseNonNull());
+ keepAliveOSREntryCallees.append(callee.releaseNonNull());
} else
m_osrEntryCallees.remove(iter);
}
diff --git a/Source/JavaScriptCore/yarr/YarrJIT.cpp b/Source/JavaScriptCore/yarr/YarrJIT.cpp
index 224ee1fb527d..dccdd0c365a0 100644
--- a/Source/JavaScriptCore/yarr/YarrJIT.cpp
+++ b/Source/JavaScriptCore/yarr/YarrJIT.cpp
@@ -1326,9 +1326,9 @@ class YarrGenerator final : public YarrJITInfo {
Checked characterOffset(-static_cast(negativeCharacterOffset));
if (m_charSize == CharSize::Char8)
- return MacroAssembler::BaseIndex(m_regs.input, indexReg, MacroAssembler::TimesOne, characterOffset * static_cast(sizeof(char)));
+ return MacroAssembler::BaseIndex(base, indexReg, MacroAssembler::TimesOne, characterOffset * static_cast(sizeof(char)));
- return MacroAssembler::BaseIndex(m_regs.input, indexReg, MacroAssembler::TimesTwo, characterOffset * static_cast(sizeof(char16_t)));
+ return MacroAssembler::BaseIndex(base, indexReg, MacroAssembler::TimesTwo, characterOffset * static_cast(sizeof(char16_t)));
}
#if ENABLE(YARR_JIT_UNICODE_EXPRESSIONS)
@@ -4525,7 +4525,7 @@ class YarrGenerator final : public YarrJITInfo {
}
++opIndex;
- } while (opIndex < m_ops.size());
+ } while (opIndex < m_ops.size() && !hasExceededCodeSizeLimit());
termMatchTargets.takeLast();
}
@@ -5332,7 +5332,18 @@ class YarrGenerator final : public YarrJITInfo {
case YarrOpCode::MatchFailed:
break;
}
- } while (opIndex);
+ } while (opIndex && !hasExceededCodeSizeLimit());
+ }
+
+ bool hasExceededCodeSizeLimit()
+ {
+ if (m_failureReason)
+ return true;
+ if (m_jit.m_assembler.buffer().codeSize() > Options::maximumRegExpJITCodeSize()) [[unlikely]] {
+ m_failureReason = JITFailureReason::GeneratedCodeSizeTooLarge;
+ return true;
+ }
+ return false;
}
// Compilation methods:
@@ -6951,9 +6962,17 @@ class YarrGenerator final : public YarrJITInfo {
generate();
if (m_disassembler)
m_disassembler->setEndOfGenerate(m_jit.label());
+ if (m_failureReason) {
+ codeBlock.setFallBackWithFailureReason(*m_failureReason);
+ return;
+ }
backtrack();
if (m_disassembler)
m_disassembler->setEndOfBacktrack(m_jit.label());
+ if (m_failureReason) {
+ codeBlock.setFallBackWithFailureReason(*m_failureReason);
+ return;
+ }
ptrdiff_t codeSize = MacroAssembler::differenceBetween(startOfMainCode, m_jit.label());
bool canInline = ([&] -> bool {
@@ -7585,6 +7604,9 @@ static void dumpCompileFailure(JITFailureReason failure)
case JITFailureReason::OffsetTooLarge:
dataLog("Can't JIT because pattern exceeds string length limits\n");
break;
+ case JITFailureReason::GeneratedCodeSizeTooLarge:
+ dataLog("Can't JIT because generated code size exceeds limit\n");
+ break;
}
}
diff --git a/Source/JavaScriptCore/yarr/YarrJIT.h b/Source/JavaScriptCore/yarr/YarrJIT.h
index caa9a4b94bc3..4932afa28a40 100644
--- a/Source/JavaScriptCore/yarr/YarrJIT.h
+++ b/Source/JavaScriptCore/yarr/YarrJIT.h
@@ -63,6 +63,7 @@ enum class JITFailureReason : uint8_t {
ParenthesisNestedTooDeep,
ExecutableMemoryAllocationFailure,
OffsetTooLarge,
+ GeneratedCodeSizeTooLarge,
};
class BoyerMooreFastCandidates {
diff --git a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj b/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj
index 643352fd41ab..9f220a9cfb6c 100644
--- a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj
+++ b/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj
@@ -479,6 +479,7 @@
7B8EC8472DF2E5FC00105EB6 /* EnsureLoopForwardProgress.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B8EC8442DF2E5FC00105EB6 /* EnsureLoopForwardProgress.h */; };
7B8EC8482DF2E5FC00105EB6 /* EnsureLoopForwardProgress.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B8EC8442DF2E5FC00105EB6 /* EnsureLoopForwardProgress.h */; };
7B8EC8492DF2E5FC00105EB6 /* EnsureLoopForwardProgress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B8EC8452DF2E5FC00105EB6 /* EnsureLoopForwardProgress.cpp */; };
+ 7B91C9A82F8CE63A00420427 /* VertexArrayMtl_unittest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7B91C9A62F8CDB5400420427 /* VertexArrayMtl_unittest.mm */; };
7B9A99BA2DDC685100160B6E /* ReduceInterfaceBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A99B92DDC685100160B6E /* ReduceInterfaceBlocks.cpp */; };
7B9A99BB2DDC685100160B6E /* ReduceInterfaceBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B9A99B82DDC685100160B6E /* ReduceInterfaceBlocks.h */; };
7B9A99BC2DDC685100160B6E /* ReduceInterfaceBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A99B92DDC685100160B6E /* ReduceInterfaceBlocks.cpp */; };
@@ -2402,6 +2403,7 @@
7B8EC83F2DF1BC9100105EB6 /* ImageTestMetal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageTestMetal.mm; sourceTree = ""; };
7B8EC8442DF2E5FC00105EB6 /* EnsureLoopForwardProgress.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnsureLoopForwardProgress.h; sourceTree = ""; };
7B8EC8452DF2E5FC00105EB6 /* EnsureLoopForwardProgress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = EnsureLoopForwardProgress.cpp; sourceTree = ""; };
+ 7B91C9A62F8CDB5400420427 /* VertexArrayMtl_unittest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VertexArrayMtl_unittest.mm; sourceTree = ""; };
7B9829372E0EB05200F1E9FB /* ANGLETranslator.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ANGLETranslator.xcconfig; sourceTree = ""; };
7B9A99B82DDC685100160B6E /* ReduceInterfaceBlocks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReduceInterfaceBlocks.h; sourceTree = ""; };
7B9A99B92DDC685100160B6E /* ReduceInterfaceBlocks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReduceInterfaceBlocks.cpp; sourceTree = ""; };
@@ -4711,6 +4713,7 @@
FF81FEA425818D6800894E24 /* TransformFeedbackMtl.mm */,
FF81FE9725818D6800894E24 /* VertexArrayMtl.h */,
FF81FE9A25818D6800894E24 /* VertexArrayMtl.mm */,
+ 7B91C9A62F8CDB5400420427 /* VertexArrayMtl_unittest.mm */,
);
path = metal;
sourceTree = "";
@@ -6547,6 +6550,7 @@
7BFAF5C12DE59E0900327F7F /* UniformTest.cpp in Sources */,
7BFAF6062DE59E0900327F7F /* UnpackAlignmentTest.cpp in Sources */,
7BFAF5F22DE59E0900327F7F /* UnpackRowLength.cpp in Sources */,
+ 7B91C9A82F8CE63A00420427 /* VertexArrayMtl_unittest.mm in Sources */,
7BFAF5FE2DE59E0900327F7F /* VertexAttributeTest.cpp in Sources */,
7BFAF5FC2DE59E0900327F7F /* ViewportTest.cpp in Sources */,
7BFAF6152DE59E2300327F7F /* WebGLCompatibilityTest.cpp in Sources */,
diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h
index 863bfaa16646..54b4e0458811 100644
--- a/Source/WTF/wtf/PlatformHave.h
+++ b/Source/WTF/wtf/PlatformHave.h
@@ -1235,6 +1235,51 @@
#define HAVE_WK_SECURE_CODING_PKDATECOMPONENTSRANGE 1
#endif
+#if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 150400) \
+ || ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 180400) \
+ || (PLATFORM(VISION) && __VISION_OS_VERSION_MIN_REQUIRED >= 20400)) \
+ || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 110400) \
+ || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 180400)
+#define HAVE_WK_SECURE_CODING_NSURLPROTECTIONSPACE 1
+#endif
+
+#if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 150400) \
+ || ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 180400) \
+ || (PLATFORM(VISION) && __VISION_OS_VERSION_MIN_REQUIRED >= 20400)) \
+ || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 110400) \
+ || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 180400)
+#define HAVE_WK_SECURE_CODING_NSURLCREDENTIAL 1
+#endif
+
+#if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 160000) \
+ || ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 190000) \
+ || (PLATFORM(VISION) && __VISION_OS_VERSION_MIN_REQUIRED >= 30000)) \
+ || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 120000) \
+ || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 190000)
+#define HAVE_WK_SECURE_CODING_SECTRUST 1
+#endif
+
+#if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 160000) \
+ || ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 190000) \
+ || (PLATFORM(VISION) && __VISION_OS_VERSION_MIN_REQUIRED >= 30000)) \
+ || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 120000) \
+ || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 190000)
+#define HAVE_WK_SECURE_CODING_AVOUTPUTCONTEXT 1
+#endif
+
+#if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 270000) \
+ || ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 270000) \
+ || (PLATFORM(VISION) && __VISION_OS_VERSION_MIN_REQUIRED >= 270000)) \
+ || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 270000) \
+ || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 270000)
+#define HAVE_WK_SECURE_CODING_PKPAYMENTMETHOD 1
+#define HAVE_WK_SECURE_CODING_PKPAYMENTTOKEN 1
+#define HAVE_WK_SECURE_CODING_PKSHIPPINGMETHOD 1
+#define HAVE_WK_SECURE_CODING_PKPAYMENTMERCHANTSESSION 1
+#define HAVE_WK_SECURE_CODING_PKPAYMENT 1
+#define HAVE_WK_SECURE_CODING_PKPAYMENTSETUPFEATURE 1
+#endif
+
#if PLATFORM(COCOA)
#define HAVE_CFNETWORK_SEPARATE_CREDENTIAL_STORAGE 1
#define HAVE_STRICT_DECODABLE_CNCONTACT 1
diff --git a/Source/WTF/wtf/TinyLRUCache.h b/Source/WTF/wtf/TinyLRUCache.h
index eb801103a79b..0c078d06ac74 100644
--- a/Source/WTF/wtf/TinyLRUCache.h
+++ b/Source/WTF/wtf/TinyLRUCache.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
namespace WTF {
@@ -44,45 +45,195 @@ templatem_findResult == this);
+ m_cache->invalidateIterators();
+ }
+ }
+
+ explicit operator bool() const
+ {
+ return m_ptr;
+ }
+
+ const ValueType& operator*() const
+ {
+ RELEASE_ASSERT(m_ptr);
+ return *m_ptr;
+ }
+
+ const ValueType* operator->() const
+ {
+ RELEASE_ASSERT(m_ptr);
+ return m_ptr;
+ }
+
+ private:
+ friend class TinyLRUCache;
+
+ using Cache = TinyLRUCache;
+
+ FindResult(const ValueType* ptr, Cache& cache)
+ : m_ptr(ptr)
+ , m_cache(ptr ? &cache : nullptr)
+ {
+ if (m_cache)
+ m_cache->trackFindResult(this);
+ }
+
+ void assertValid() const
+ {
+ RELEASE_ASSERT_IMPLIES(m_ptr, m_cache);
+ }
+
+ const ValueType* m_ptr { nullptr };
+ Cache* m_cache { nullptr };
+ };
+
const ValueType& get(const KeyType& key)
{
+ invalidateIterators();
+
if (Policy::isKeyNull(key)) {
static NeverDestroyed valueForNull = Policy::createValueForNullKey();
return valueForNull;
}
+ if (auto* found = findInternal(key))
+ return *found;
+
+ insertInternal(key, Policy::createValueForKey(key));
+ return cacheBuffer()[m_size - 1].second;
+ }
+
+ FindResult findIfCached(const KeyType& key)
+ {
+ invalidateIterators();
+
+ if (Policy::isKeyNull(key))
+ return { nullptr, *this };
+
+ return { findInternal(key), *this };
+ }
+
+ void insert(const KeyType& key, ValueType&& value)
+ {
+ ASSERT(!Policy::isKeyNull(key));
+#if ASSERT_ENABLED
+ {
+ auto cacheBuffer = this->cacheBuffer();
+ for (size_t i = 0; i < m_size; ++i)
+ ASSERT(!(cacheBuffer[i].first == key));
+ }
+#endif
+ invalidateIterators();
+ insertInternal(key, WTF::move(value));
+ }
+
+ void clear()
+ {
+ invalidateIterators();
+ auto cacheBuffer = this->cacheBuffer();
+ for (size_t i = 0; i < m_size; ++i)
+ cacheBuffer[i] = Entry { };
+ m_size = 0;
+ }
+
+ size_t size() const { return m_size; }
+
+private:
+ void trackFindResult(FindResult* p)
+ {
+ ASSERT(p);
+ ASSERT(m_findResult != p);
+ invalidateIterators();
+ m_findResult = p;
+ }
+
+ void invalidateIterators()
+ {
+ if (m_findResult) {
+ ASSERT(m_findResult->m_cache == this);
+ m_findResult->m_cache = nullptr;
+ m_findResult->m_ptr = nullptr;
+ m_findResult = nullptr;
+ }
+ }
+
+ ALWAYS_INLINE const ValueType* findInternal(const KeyType& key)
+ {
auto cacheBuffer = this->cacheBuffer();
for (size_t i = m_size; i-- > 0;) {
if (cacheBuffer[i].first == key) {
if (i < m_size - 1) {
- // Move entry to the end of the cache if necessary.
auto entry = WTF::move(cacheBuffer[i]);
do {
cacheBuffer[i] = WTF::move(cacheBuffer[i + 1]);
} while (++i < m_size - 1);
cacheBuffer[m_size - 1] = WTF::move(entry);
}
- return cacheBuffer[m_size - 1].second;
+ return &cacheBuffer[m_size - 1].second;
}
}
+ return nullptr;
+ }
- // cacheBuffer[0] is the LRU entry, so remove it.
+ ALWAYS_INLINE void insertInternal(const KeyType& key, ValueType&& value)
+ {
+ auto cacheBuffer = this->cacheBuffer();
if (m_size == capacity) {
for (size_t i = 0; i < m_size - 1; ++i)
cacheBuffer[i] = WTF::move(cacheBuffer[i + 1]);
} else
++m_size;
-
- cacheBuffer[m_size - 1] = std::pair { Policy::createKeyForStorage(key), Policy::createValueForKey(key) };
- return cacheBuffer[m_size - 1].second;
+ cacheBuffer[m_size - 1] = std::pair { Policy::createKeyForStorage(key), WTF::move(value) };
}
-private:
using Entry = std::pair;
std::span cacheBuffer() { return m_cacheBuffer; }
alignas(Entry) std::array m_cacheBuffer;
size_t m_size { 0 };
+ FindResult* m_findResult { nullptr };
};
} // namespace WTF
diff --git a/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp b/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp
index 99773da3464b..f054bb5150fd 100644
--- a/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp
+++ b/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp
@@ -221,7 +221,12 @@ void MemoryIndexCursor::indexRecordsAllChanged()
void MemoryIndexCursor::indexValueChanged(const IDBKeyData& key, const IDBKeyData& primaryKey)
{
- if (m_currentKey != key || m_currentPrimaryKey != primaryKey)
+ // For Prev/Prevunique cursors, m_currentIterator wraps std::set reverse_iterators
+ // whose stored base() points one element past the logical position. Erasing that
+ // adjacent element leaves base() dangling even though m_currentKey/m_currentPrimaryKey
+ // are unchanged, so for reverse cursors we must invalidate on any index mutation
+ // and let iterate() re-seek via reverseFind().
+ if (info().isDirectionForward() && (m_currentKey != key || m_currentPrimaryKey != primaryKey))
return;
m_currentIterator.invalidate();
diff --git a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
index 7fea86ececa1..5e2024f19b39 100644
--- a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
+++ b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
@@ -1379,6 +1379,11 @@ void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection&
handleTransactions();
}
+bool UniqueIDBDatabase::isVersionChangeTransactionActive(const UniqueIDBDatabaseConnection& connection) const
+{
+ return m_versionChangeDatabaseConnection == &connection && m_versionChangeTransaction;
+}
+
void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
{
ASSERT(!isMainThread());
diff --git a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
index b934e0720987..5a49d2aaa7b5 100644
--- a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
+++ b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
@@ -110,6 +110,7 @@ class UniqueIDBDatabase final : public CanMakeWeakPtr, public
void didFinishHandlingVersionChange(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& transactionIdentifier);
void connectionClosedFromClient(UniqueIDBDatabaseConnection&);
+ WEBCORE_EXPORT bool isVersionChangeTransactionActive(const UniqueIDBDatabaseConnection&) const;
void didFireVersionChangeEvent(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& requestIdentifier, IndexedDB::ConnectionClosedOnBehalfOfServer);
WEBCORE_EXPORT void openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier);
diff --git a/Source/WebCore/Modules/mediasession/MediaMetadata.cpp b/Source/WebCore/Modules/mediasession/MediaMetadata.cpp
index f3d7164e63a8..2b7a6408cccb 100644
--- a/Source/WebCore/Modules/mediasession/MediaMetadata.cpp
+++ b/Source/WebCore/Modules/mediasession/MediaMetadata.cpp
@@ -270,14 +270,17 @@ void MediaMetadata::tryNextArtworkImage(uint32_t index, Vector&& artworks)
String artworkImageSrc = artworks[index].src;
- m_artworkLoader = ArtworkImageLoader::create(*document, artworkImageSrc, [this, index, artworkImageSrc, artworks = WTF::move(artworks)](Image* image) mutable {
+ m_artworkLoader = ArtworkImageLoader::create(*document, artworkImageSrc, [weakThis = WeakPtr { *this }, index, artworkImageSrc, artworks = WTF::move(artworks)](Image* image) mutable {
+ RefPtr strongThis = weakThis;
+ if (!strongThis)
+ return;
if (image && image->data() && image->width() && image->height()) {
IntSize size { int(image->width()), int(image->height()) };
float imageScore = imageDimensionsScore(size.width(), size.height(), s_minimumSize, s_idealSize);
- if (!index || (m_artworkImage && (imageDimensionsScore(protect(m_artworkImage)->width(), protect(m_artworkImage)->height(), s_minimumSize, s_idealSize) < imageScore))) {
- m_artworkImageSrc = artworkImageSrc;
- setArtworkImage(image);
- metadataUpdated();
+ if (!index || (strongThis->m_artworkImage && (imageDimensionsScore(protect(strongThis->m_artworkImage)->width(), protect(strongThis->m_artworkImage)->height(), s_minimumSize, s_idealSize) < imageScore))) {
+ strongThis->m_artworkImageSrc = artworkImageSrc;
+ strongThis->setArtworkImage(image);
+ strongThis->metadataUpdated();
}
// If selection from `sizes` attribute yielded a valid image, or we have downloaded an image bigger than the ideal size we stop.
if (artworks[index].score >= 0 || size.maxDimension() >= s_idealSize)
@@ -285,7 +288,7 @@ void MediaMetadata::tryNextArtworkImage(uint32_t index, Vector&& artworks)
}
if (++index < artworks.size())
- tryNextArtworkImage(index, WTF::move(artworks));
+ strongThis->tryNextArtworkImage(index, WTF::move(artworks));
});
protect(m_artworkLoader)->requestImageResource();
}
diff --git a/Source/WebCore/Modules/mediasession/MediaMetadata.h b/Source/WebCore/Modules/mediasession/MediaMetadata.h
index a4d20458a387..932c83f49997 100644
--- a/Source/WebCore/Modules/mediasession/MediaMetadata.h
+++ b/Source/WebCore/Modules/mediasession/MediaMetadata.h
@@ -75,7 +75,7 @@ class ArtworkImageLoader final : public CachedImageClient, public RefCounted m_cachedImage;
};
-class MediaMetadata final : public RefCounted {
+class MediaMetadata final : public RefCountedAndCanMakeWeakPtr {
public:
static ExceptionOr[> create(ScriptExecutionContext&, std::optional]&&);
static Ref create(MediaSession&, Vector&&);
diff --git a/Source/WebCore/Modules/mediasource/MediaSource.cpp b/Source/WebCore/Modules/mediasource/MediaSource.cpp
index 10291bce97b3..82d59f918bc5 100644
--- a/Source/WebCore/Modules/mediasource/MediaSource.cpp
+++ b/Source/WebCore/Modules/mediasource/MediaSource.cpp
@@ -264,7 +264,6 @@ void MediaSource::setPrivateAndOpen(Ref&& mediaSourcePrivate
ASSERT(!m_private);
setPrivate(WTF::move(mediaSourcePrivate));
- protect(m_private)->setTimeFudgeFactor(currentTimeFudgeFactor());
open();
}
@@ -405,13 +404,6 @@ ExceptionOr MediaSource::clearLiveSeekableRange()
return { };
}
-const MediaTime& MediaSource::currentTimeFudgeFactor()
-{
- // Allow hasCurrentTime() to be off by as much as the length of two 24fps video frames
- static NeverDestroyed fudgeFactor(2002, 24000);
- return fudgeFactor;
-}
-
bool MediaSource::contentTypeShouldGenerateTimestamps(const ContentType& contentType)
{
return contentType.containerType() == "audio/aac"_s || contentType.containerType() == "audio/mpeg"_s;
diff --git a/Source/WebCore/Modules/mediasource/MediaSource.h b/Source/WebCore/Modules/mediasource/MediaSource.h
index 238194945d61..90a305ba6c4e 100644
--- a/Source/WebCore/Modules/mediasource/MediaSource.h
+++ b/Source/WebCore/Modules/mediasource/MediaSource.h
@@ -136,7 +136,6 @@ class MediaSource
ScriptExecutionContext* NODELETE scriptExecutionContext() const final;
- static const MediaTime& NODELETE currentTimeFudgeFactor();
static bool contentTypeShouldGenerateTimestamps(const ContentType&);
#if !RELEASE_LOG_DISABLED
diff --git a/Source/WebCore/Modules/web-locks/WebLockManager.cpp b/Source/WebCore/Modules/web-locks/WebLockManager.cpp
index 32bbd739d03f..69691abf3fa7 100644
--- a/Source/WebCore/Modules/web-locks/WebLockManager.cpp
+++ b/Source/WebCore/Modules/web-locks/WebLockManager.cpp
@@ -96,8 +96,8 @@ class WebLockManager::MainThreadBridge : public ThreadSafeRefCounted&&, Function&& lockStolenHandler);
void releaseLock(WebLockIdentifier, const String& name);
- void abortLockRequest(WebLockIdentifier, const String& name, CompletionHandler&&);
- void query(CompletionHandler&&);
+ void abortLockRequest(WebLockIdentifier, const String& name, Function&&);
+ void query(Function&&);
void clientIsGoingAway();
private:
@@ -137,23 +137,23 @@ void WebLockManager::MainThreadBridge::releaseLock(WebLockIdentifier lockIdentif
});
}
-void WebLockManager::MainThreadBridge::abortLockRequest(WebLockIdentifier lockIdentifier, const String& name, CompletionHandler&& completionHandler)
+void WebLockManager::MainThreadBridge::abortLockRequest(WebLockIdentifier lockIdentifier, const String& name, Function&& callback)
{
- callOnMainThread([this, protectedThis = Ref { *this }, lockIdentifier, name = crossThreadCopy(name), completionHandler = WTF::move(completionHandler)]() mutable {
- WebLockRegistry::singleton().abortLockRequest(m_sessionID, m_clientOrigin, lockIdentifier, m_clientID, name, [clientID = m_clientID, completionHandler = WTF::move(completionHandler)](bool wasAborted) mutable {
- ScriptExecutionContext::ensureOnContextThread(clientID, [completionHandler = WTF::move(completionHandler), wasAborted](auto&) mutable {
- completionHandler(wasAborted);
+ callOnMainThread([this, protectedThis = Ref { *this }, lockIdentifier, name = crossThreadCopy(name), callback = WTF::move(callback)]() mutable {
+ WebLockRegistry::singleton().abortLockRequest(m_sessionID, m_clientOrigin, lockIdentifier, m_clientID, name, [clientID = m_clientID, callback = WTF::move(callback)](bool wasAborted) mutable {
+ ScriptExecutionContext::ensureOnContextThread(clientID, [callback = WTF::move(callback), wasAborted](auto&) mutable {
+ callback(wasAborted);
});
});
});
}
-void WebLockManager::MainThreadBridge::query(CompletionHandler&& completionHandler)
+void WebLockManager::MainThreadBridge::query(Function&& callback)
{
- callOnMainThread([this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler)]() mutable {
- WebLockRegistry::singleton().snapshot(m_sessionID, m_clientOrigin, [clientID = m_clientID, completionHandler = WTF::move(completionHandler)](Snapshot&& snapshot) mutable {
- ScriptExecutionContext::ensureOnContextThread(clientID, [completionHandler = WTF::move(completionHandler), snapshot = crossThreadCopy(snapshot)](auto&) mutable {
- completionHandler(WTF::move(snapshot));
+ callOnMainThread([this, protectedThis = Ref { *this }, callback = WTF::move(callback)]() mutable {
+ WebLockRegistry::singleton().snapshot(m_sessionID, m_clientOrigin, [clientID = m_clientID, callback = WTF::move(callback)](Snapshot&& snapshot) mutable {
+ ScriptExecutionContext::ensureOnContextThread(clientID, [callback = WTF::move(callback), snapshot = crossThreadCopy(snapshot)](auto&) mutable {
+ callback(WTF::move(snapshot));
});
});
});
@@ -322,11 +322,17 @@ void WebLockManager::query(Ref&& promise)
return;
}
- m_mainThreadBridge->query([weakThis = WeakPtr { *this }, promise = WTF::move(promise)](Snapshot&& snapshot) mutable {
+ auto promiseIdentifier = WebLockIdentifier::generate();
+ m_queryPromises.add(promiseIdentifier, WTF::move(promise));
+ m_mainThreadBridge->query([weakThis = WeakPtr { *this }, promiseIdentifier](Snapshot&& snapshot) mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis)
return;
+ auto promise = protectedThis->m_queryPromises.take(promiseIdentifier);
+ if (!promise)
+ return;
+
queueTaskKeepingObjectAlive(*protectedThis, TaskSource::DOMManipulation, [promise = WTF::move(promise), snapshot = WTF::move(snapshot)](auto&) mutable {
promise->resolve>(WTF::move(snapshot));
});
@@ -373,16 +379,16 @@ void WebLockManager::stop()
void WebLockManager::clientIsGoingAway()
{
- if (m_pendingRequests.isEmpty() && m_releasePromises.isEmpty())
- return;
-
for (auto& request : m_pendingRequests.values())
request.removeSignalAlgorithm();
- // Reject all pending promises before clearing
- for (Ref promise : m_releasePromises.values())
- promise->reject(ExceptionCode::AbortError, "Promise was rejected because the browsing context is going away"_s);
-
+ // Reject all pending promises before clearing.
+ auto releasePromises = std::exchange(m_releasePromises, { });
+ for (auto& promise : releasePromises.values())
+ protect(promise)->reject(ExceptionCode::AbortError, "Promise was rejected because the browsing context is going away"_s);
+ auto queryPromises = std::exchange(m_queryPromises, { });
+ for (auto& promise : queryPromises.values())
+ protect(promise)->reject(ExceptionCode::AbortError, "Promise was rejected because the browsing context is going away"_s);
m_pendingRequests.clear();
m_releasePromises.clear();
@@ -392,7 +398,7 @@ void WebLockManager::clientIsGoingAway()
bool WebLockManager::virtualHasPendingActivity() const
{
- return !m_pendingRequests.isEmpty() || !m_releasePromises.isEmpty();
+ return !m_pendingRequests.isEmpty() || !m_releasePromises.isEmpty() || !m_queryPromises.isEmpty();
}
void WebLockManager::suspend(ReasonForSuspension reason)
diff --git a/Source/WebCore/Modules/web-locks/WebLockManager.h b/Source/WebCore/Modules/web-locks/WebLockManager.h
index 22a8294a448b..14d5fd99bb1a 100644
--- a/Source/WebCore/Modules/web-locks/WebLockManager.h
+++ b/Source/WebCore/Modules/web-locks/WebLockManager.h
@@ -83,6 +83,8 @@ class WebLockManager : public RefCounted, public ActiveDOMObject
struct LockRequest;
HashMap m_pendingRequests;
+
+ HashMap> m_queryPromises;
};
} // namespace WebCore
diff --git a/Source/WebCore/Modules/webaudio/BiquadFilterNode.cpp b/Source/WebCore/Modules/webaudio/BiquadFilterNode.cpp
index 501879620549..795387fc6b52 100644
--- a/Source/WebCore/Modules/webaudio/BiquadFilterNode.cpp
+++ b/Source/WebCore/Modules/webaudio/BiquadFilterNode.cpp
@@ -28,6 +28,8 @@
#if ENABLE(WEB_AUDIO)
#include "BiquadFilterNode.h"
+
+#include "BaseAudioContext.h"
#include "ExceptionOr.h"
#include
#include
@@ -70,6 +72,11 @@ BiquadFilterType BiquadFilterNode::type() const
void BiquadFilterNode::setType(BiquadFilterType type)
{
+ ASSERT(isMainThread());
+
+ // Synchronize with any graph changes or changes to channel configuration since
+ // BiquadProcessor::setType() may iterate the processor's kernels via reset().
+ Locker contextLocker { context().graphLock() };
protect(biquadProcessor())->setType(type);
}
diff --git a/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.cpp b/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.cpp
index 8f6e315aeed6..d9d428f08a7e 100644
--- a/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.cpp
+++ b/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.cpp
@@ -65,6 +65,7 @@ WebCodecsAudioData::WebCodecsAudioData(ScriptExecutionContext& context)
WebCodecsAudioData::WebCodecsAudioData(ScriptExecutionContext& context, WebCodecsAudioInternalData&& data)
: ContextDestructionObserver(&context)
, m_data(WTF::move(data))
+ , m_memoryCost(m_data.memoryCost())
{
}
@@ -151,6 +152,7 @@ ExceptionOr[> WebCodecsAudioData::clone(ScriptExecutionCo
// https://www.w3.org/TR/webcodecs/#dom-audiodata-close
void WebCodecsAudioData::close()
{
+ m_memoryCost.store(0, std::memory_order_relaxed);
m_data.audioData = nullptr;
m_isDetached = true;
diff --git a/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.h b/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.h
index 97b6e9b3244c..46cd29c6295e 100644
--- a/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.h
+++ b/Source/WebCore/Modules/webcodecs/WebCodecsAudioData.h
@@ -84,13 +84,16 @@ class WebCodecsAudioData : public RefCounted], public Context
const WebCodecsAudioInternalData& data() const LIFETIME_BOUND { return m_data; }
- size_t memoryCost() const { return m_data.memoryCost(); }
+ // memoryCost() may be called from a GC thread by the JS wrapper's visitChildren, so it must
+ // not touch m_data.audioData (which close() may concurrently null on the main thread).
+ size_t memoryCost() const { return m_memoryCost.load(std::memory_order_relaxed); }
private:
explicit WebCodecsAudioData(ScriptExecutionContext&);
WebCodecsAudioData(ScriptExecutionContext&, WebCodecsAudioInternalData&&);
WebCodecsAudioInternalData m_data;
+ std::atomic m_memoryCost { 0 };
bool m_isDetached { false };
};
diff --git a/Source/WebCore/bindings/js/JSDOMOperationReturningPromise.h b/Source/WebCore/bindings/js/JSDOMOperationReturningPromise.h
index 78c4c04cfed0..ec257c3f3264 100644
--- a/Source/WebCore/bindings/js/JSDOMOperationReturningPromise.h
+++ b/Source/WebCore/bindings/js/JSDOMOperationReturningPromise.h
@@ -56,10 +56,10 @@ class IDLOperationReturningPromise {
}
using Operation2 = JSC::EncodedJSValue(JSC::JSGlobalObject*, JSC::CallFrame*, ClassParameter, Ref&&, Ref&&);
- template
+ template
static JSC::EncodedJSValue callReturningPromisePair(JSC::JSGlobalObject& lexicalGlobalObject, JSC::CallFrame& callFrame, const char* operationName)
{
- return callPromisePairFunction(lexicalGlobalObject, callFrame, [&operationName] (JSC::JSGlobalObject& lexicalGlobalObject, JSC::CallFrame& callFrame, Ref&& promise, Ref&& promise2) {
+ return callPromisePairFunction(lexicalGlobalObject, callFrame, [&operationName] (JSC::JSGlobalObject& lexicalGlobalObject, JSC::CallFrame& callFrame, Ref&& promise, Ref&& promise2) {
auto* thisObject = IDLOperation::cast(lexicalGlobalObject, callFrame);
if constexpr (shouldThrow != CastedThisErrorBehavior::Assert) {
if (!thisObject) [[unlikely]]
diff --git a/Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp b/Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp
index d35cecd44b73..04a0e024c3c4 100644
--- a/Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp
+++ b/Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp
@@ -250,18 +250,30 @@ void DeferredPromise::reject(ExceptionCode ec, const String& message, RejectAsHa
handleUncaughtException(scope, lexicalGlobalObject);
}
-void rejectPromiseWithExceptionIfAny(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, JSPromise& promise, JSC::TopExceptionScope& catchScope)
+static JSValue takeNonTerminationException(JSC::TopExceptionScope& catchScope)
{
- UNUSED_PARAM(lexicalGlobalObject);
if (!catchScope.exception()) [[likely]]
- return;
+ return { };
if (catchScope.vm().hasPendingTerminationException())
- return;
+ return { };
JSValue error = catchScope.exception()->value();
catchScope.clearException();
+ return error;
+}
+
+void rejectPromiseWithExceptionIfAny(JSC::JSGlobalObject&, JSDOMGlobalObject& globalObject, JSPromise& promise, JSC::TopExceptionScope& catchScope)
+{
+ if (auto error = takeNonTerminationException(catchScope)) [[unlikely]]
+ DeferredPromise::create(globalObject, promise)->reject(error);
+}
- DeferredPromise::create(globalObject, promise)->reject(error);
+void rejectPromisesWithExceptionIfAny(JSC::JSGlobalObject&, JSDOMGlobalObject& globalObject, JSPromise& promise1, JSPromise& promise2, JSC::TopExceptionScope& catchScope)
+{
+ if (auto error = takeNonTerminationException(catchScope)) [[unlikely]] {
+ DeferredPromise::create(globalObject, promise1)->reject(error);
+ DeferredPromise::create(globalObject, promise2)->reject(error);
+ }
}
JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::JSGlobalObject& lexicalGlobalObject, const String& errorMessage, RejectedPromiseWithTypeErrorCause cause)
diff --git a/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h b/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h
index 69ac0663fad3..d4b41e5aa3c4 100644
--- a/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h
+++ b/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
@@ -373,6 +374,7 @@ void fulfillPromiseWithArrayBufferFromSpan(Ref&&, std::span&&, Uint8Array*);
void fulfillPromiseWithUint8ArrayFromSpan(Ref&&, std::span);
WEBCORE_EXPORT void rejectPromiseWithExceptionIfAny(JSC::JSGlobalObject&, JSDOMGlobalObject&, JSC::JSPromise&, JSC::TopExceptionScope&);
+WEBCORE_EXPORT void rejectPromisesWithExceptionIfAny(JSC::JSGlobalObject&, JSDOMGlobalObject&, JSC::JSPromise&, JSC::JSPromise&, JSC::TopExceptionScope&);
enum class RejectedPromiseWithTypeErrorCause { NativeGetter, InvalidThis };
JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::JSGlobalObject&, const String&, RejectedPromiseWithTypeErrorCause);
@@ -422,26 +424,34 @@ inline JSC::JSValue callPromiseFunction(JSC::JSGlobalObject& lexicalGlobalObject
using PromisePairFunction = JSC::EncodedJSValue(JSC::JSGlobalObject&, JSC::CallFrame&, Ref&&, Ref&&);
-template
+template
inline JSC::EncodedJSValue callPromisePairFunction(JSC::JSGlobalObject& lexicalGlobalObject, JSC::CallFrame& callFrame, PromisePairFunctor functor)
{
JSC::VM& vm = JSC::getVM(&lexicalGlobalObject);
auto catchScope = DECLARE_TOP_EXCEPTION_SCOPE(vm);
auto& globalObject = downcast(lexicalGlobalObject);
- auto* promise = JSC::JSPromise::create(vm, globalObject.promiseStructure());
- ASSERT(promise);
+ auto* promise1 = JSC::JSPromise::create(vm, globalObject.promiseStructure());
+ ASSERT(promise1);
auto* promise2 = JSC::JSPromise::create(vm, globalObject.promiseStructure());
ASSERT(promise2);
- auto result = functor(globalObject, callFrame, DeferredPromise::create(globalObject, *promise, DeferredPromise::Mode::RetainPromiseOnResolve), DeferredPromise::create(globalObject, *promise2, DeferredPromise::Mode::RetainPromiseOnResolve));
+ auto result = functor(globalObject, callFrame, DeferredPromise::create(globalObject, *promise1, DeferredPromise::Mode::RetainPromiseOnResolve), DeferredPromise::create(globalObject, *promise2, DeferredPromise::Mode::RetainPromiseOnResolve));
+
+ rejectPromisesWithExceptionIfAny(lexicalGlobalObject, globalObject, *promise1, *promise2, catchScope);
- rejectPromiseWithExceptionIfAny(lexicalGlobalObject, globalObject, *promise, catchScope);
- rejectPromiseWithExceptionIfAny(lexicalGlobalObject, globalObject, *promise2, catchScope);
// FIXME: We could have error since any JS call can throw stack-overflow errors.
// https://bugs.webkit.org/show_bug.cgi?id=203402
RETURN_IF_EXCEPTION(catchScope, JSC::encodedJSValue());
+ // When the functor threw (e.g. during IDL argument conversion), its return
+ // value is an empty JSValue sentinel. Rebuild a valid result dictionary from
+ // the (now rejected) promises via convertDictionaryToJS.
+ if (!JSC::JSValue::decode(result)) [[unlikely]] {
+ result = JSC::JSValue::encode(convertDictionaryToJS(lexicalGlobalObject, globalObject, DictionaryType { DOMPromise::create(globalObject, *promise1), DOMPromise::create(globalObject, *promise2) }));
+ RETURN_IF_EXCEPTION(catchScope, JSC::encodedJSValue());
+ }
+
return result;
}
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
index cc5689700415..a8f0269ae14c 100644
--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -6369,6 +6369,11 @@ sub GenerateOperationTrampolineDefinition
my @callFunctionTemplateArguments = ();
push(@callFunctionTemplateArguments, $functionBodyName);
+ if ($operation->extendedAttributes->{ReturnsPromisePair}) {
+ my $dictClassName = GetDictionaryClassName($operation->type, $interface);
+ push(@callFunctionTemplateArguments, $dictClassName);
+ AddToImplIncludes("JSDOMPromise.h", $operation->extendedAttributes->{Conditional});
+ }
push(@callFunctionTemplateArguments, "CastedThisErrorBehavior::Assert") if ($operation->extendedAttributes->{PrivateIdentifier} and not $operation->extendedAttributes->{PublicIdentifier});
push(@$outputArray, "JSC_DEFINE_HOST_FUNCTION(${functionName}, (JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame))\n");
diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
index a7d0cf0d81cc..b4acba80feee 100644
--- a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
@@ -65,6 +65,7 @@
#include "JSDOMIterator.h"
#include "JSDOMOperation.h"
#include "JSDOMOperationReturningPromise.h"
+#include "JSDOMPromise.h"
#include "JSDOMStringList.h"
#include "JSDOMWindowBase.h"
#include "JSDOMWrapperCache.h"
@@ -7824,7 +7825,7 @@ static inline JSC::EncodedJSValue jsTestObjPrototypeFunction_returnsPromisePairB
JSC_DEFINE_HOST_FUNCTION(jsTestObjPrototypeFunction_returnsPromisePair, (JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame))
{
- return IDLOperationReturningPromise::callReturningPromisePair(*lexicalGlobalObject, *callFrame, "returnsPromisePair");
+ return IDLOperationReturningPromise::callReturningPromisePair(*lexicalGlobalObject, *callFrame, "returnsPromisePair");
}
#if ENABLE(TEST_FEATURE)
diff --git a/Source/WebCore/css/CSSFunctionRule.cpp b/Source/WebCore/css/CSSFunctionRule.cpp
index 72f8f6eaec7f..85cc8f439fbe 100644
--- a/Source/WebCore/css/CSSFunctionRule.cpp
+++ b/Source/WebCore/css/CSSFunctionRule.cpp
@@ -50,9 +50,11 @@ auto CSSFunctionRule::getParameters() const -> Vector
{
return WTF::map(styleRuleFunction().parameters(), [](const auto& parameter) {
RefPtr defaultValue = parameter.defaultValue;
+ StringBuilder type;
+ serializeCustomPropertySyntax(type, parameter.type);
return FunctionParameter {
.name = parameter.name,
- .type = "*"_s, // FIXME: Implement.
+ .type = type.toString(),
// FIXME: The spec says:
// "The default value of the function parameter, or `null` if the argument does not have a default".
// But WPT tests currently expect the value to missing/undefined, not `null`, so we are using
@@ -64,7 +66,9 @@ auto CSSFunctionRule::getParameters() const -> Vector
String CSSFunctionRule::returnType() const
{
- return "*"_s;
+ StringBuilder builder;
+ serializeCustomPropertySyntax(builder, styleRuleFunction().returnType());
+ return builder.toString();
}
String CSSFunctionRule::cssText() const
@@ -78,14 +82,25 @@ String CSSFunctionRule::cssText() const
for (auto& parameter : styleRuleFunction().parameters()) {
builder.append(separator);
serializeIdentifier(builder, parameter.name);
- // FIXME: Serialize the type.
+
+ if (!parameter.type.isUniversal()) {
+ builder.append(' ');
+ serializeCustomPropertySyntaxAsCSSType(builder, parameter.type);
+ }
if (RefPtr defaultValue = parameter.defaultValue)
builder.append(": "_s, defaultValue->serialize());
separator = ", "_s;
}
- builder.append(") { "_s);
+ builder.append(')');
+
+ if (auto& returnType = styleRuleFunction().returnType(); !returnType.isUniversal()) {
+ builder.append(" returns "_s);
+ serializeCustomPropertySyntaxAsCSSType(builder, returnType);
+ }
+
+ builder.append(" { "_s);
for (unsigned index = 0; index < length(); ++index) {
Ref rule = *item(index);
diff --git a/Source/WebCore/css/StyleProperties.cpp b/Source/WebCore/css/StyleProperties.cpp
index 2d1877a3e852..0ade9334464c 100644
--- a/Source/WebCore/css/StyleProperties.cpp
+++ b/Source/WebCore/css/StyleProperties.cpp
@@ -25,6 +25,7 @@
#include "CSSColorValue.h"
#include "CSSCustomPropertyValue.h"
+#include "CSSMarkup.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyInitialValues.h"
#include "CSSPropertyNames.h"
@@ -305,7 +306,7 @@ StringBuilder StyleProperties::asTextInternal(const CSS::SerializationContext& c
result.append(' ');
if (propertyID == CSSPropertyCustom)
- result.append(downcast(*property.value()).name());
+ serializeIdentifier(result, downcast(*property.value()).name());
else
result.append(nameLiteral(propertyID));
diff --git a/Source/WebCore/css/parser/CSSCustomPropertySyntax.cpp b/Source/WebCore/css/parser/CSSCustomPropertySyntax.cpp
index 0cd7f30ce86c..f8088f756f1e 100644
--- a/Source/WebCore/css/parser/CSSCustomPropertySyntax.cpp
+++ b/Source/WebCore/css/parser/CSSCustomPropertySyntax.cpp
@@ -25,12 +25,14 @@
#include "config.h"
#include "CSSCustomPropertySyntax.h"
+#include "CSSMarkup.h"
#include "CSSParserIdioms.h"
#include "CSSParserTokenRange.h"
#include "CSSPropertyParserConsumer+Primitives.h"
#include "CSSTokenizer.h"
#include
#include
+#include
namespace WebCore {
@@ -205,4 +207,74 @@ auto CSSCustomPropertySyntax::typeForTypeName(StringView dataTypeName) -> Type
return typeMap.get(dataTypeName, Type::Unknown);
}
+static ASCIILiteral typeNameForType(CSSCustomPropertySyntax::Type type)
+{
+ using Type = CSSCustomPropertySyntax::Type;
+ switch (type) {
+ case Type::Length: return "length"_s;
+ case Type::LengthPercentage: return "length-percentage"_s;
+ case Type::Percentage: return "percentage"_s;
+ case Type::Integer: return "integer"_s;
+ case Type::Number: return "number"_s;
+ case Type::Angle: return "angle"_s;
+ case Type::Time: return "time"_s;
+ case Type::Resolution: return "resolution"_s;
+ case Type::Color: return "color"_s;
+ case Type::Image: return "image"_s;
+ case Type::URL: return "url"_s;
+ case Type::CustomIdent: return "custom-ident"_s;
+ case Type::String: return "string"_s;
+ case Type::TransformFunction: return "transform-function"_s;
+ case Type::TransformList: return "transform-list"_s;
+ case Type::Ident:
+ case Type::Unknown:
+ break;
+ }
+ return { };
+}
+
+void serializeCustomPropertySyntax(StringBuilder& builder, const CSSCustomPropertySyntax& syntax)
+{
+ if (syntax.isUniversal()) {
+ builder.append('*');
+ return;
+ }
+
+ auto separator = ""_s;
+ for (auto& component : syntax.definition) {
+ builder.append(separator);
+ separator = " | "_s;
+
+ // The Ident type is a literal custom identifier rather than a named data type.
+ if (component.type == CSSCustomPropertySyntax::Type::Ident)
+ serializeIdentifier(builder, component.ident);
+ else
+ builder.append('<', typeNameForType(component.type), '>');
+
+ switch (component.multiplier) {
+ case CSSCustomPropertySyntax::Multiplier::Single:
+ break;
+ case CSSCustomPropertySyntax::Multiplier::SpaceList:
+ builder.append('+');
+ break;
+ case CSSCustomPropertySyntax::Multiplier::CommaList:
+ builder.append('#');
+ break;
+ }
+ }
+}
+
+void serializeCustomPropertySyntaxAsCSSType(StringBuilder& builder, const CSSCustomPropertySyntax& syntax)
+{
+ ASSERT(!syntax.isUniversal());
+ // A single syntax component is written bare. Anything else must be wrapped in type().
+ if (syntax.definition.size() == 1) {
+ serializeCustomPropertySyntax(builder, syntax);
+ return;
+ }
+ builder.append("type("_s);
+ serializeCustomPropertySyntax(builder, syntax);
+ builder.append(')');
+}
+
}
diff --git a/Source/WebCore/css/parser/CSSCustomPropertySyntax.h b/Source/WebCore/css/parser/CSSCustomPropertySyntax.h
index 2c3e43f69a9f..f4af5605b3d5 100644
--- a/Source/WebCore/css/parser/CSSCustomPropertySyntax.h
+++ b/Source/WebCore/css/parser/CSSCustomPropertySyntax.h
@@ -27,6 +27,10 @@
#include
#include
+namespace WTF {
+class StringBuilder;
+}
+
namespace WebCore {
class CSSParserTokenRange;
@@ -73,7 +77,6 @@ struct CSSCustomPropertySyntax {
static std::optional parse(StringView);
static std::optional consumeType(CSSParserTokenRange&);
-
static CSSCustomPropertySyntax universal() { return { }; }
bool NODELETE containsUnknownType() const;
@@ -83,4 +86,11 @@ struct CSSCustomPropertySyntax {
static Type typeForTypeName(StringView);
};
+// Serializes to the string form, e.g. "*", "", "+", " | ".
+void serializeCustomPropertySyntax(StringBuilder&, const CSSCustomPropertySyntax&);
+
+// Serializes to the form used in @function preludes: a single component is bare, while a
+// multi-component syntax is wrapped in type(). Must not be called on the universal syntax.
+void serializeCustomPropertySyntaxAsCSSType(StringBuilder&, const CSSCustomPropertySyntax&);
+
}
diff --git a/Source/WebCore/dom/DocumentStorageAccess.cpp b/Source/WebCore/dom/DocumentStorageAccess.cpp
index 3ba8a7e499a5..54adf96d04c6 100644
--- a/Source/WebCore/dom/DocumentStorageAccess.cpp
+++ b/Source/WebCore/dom/DocumentStorageAccess.cpp
@@ -238,8 +238,8 @@ void DocumentStorageAccess::requestStorageAccess(Ref&& promise)
if (!page->settings().storageAccessAPIPerPageScopeEnabled())
m_storageAccessScope = StorageAccessScope::PerFrame;
- auto hasOrShouldIgnoreUserGesture = frame->requestSkipUserActivationCheckForStorageAccess(RegistrableDomain { document->url() }) || UserGestureIndicator::processingUserGesture() ? HasOrShouldIgnoreUserGesture::Yes : HasOrShouldIgnoreUserGesture::No;
- page->chrome().client().requestStorageAccess(RegistrableDomain::uncheckedCreateFromHost(protect(document->securityOrigin())->host()), RegistrableDomain::uncheckedCreateFromHost(protect(document->topOrigin())->host()), *frame, m_storageAccessScope, hasOrShouldIgnoreUserGesture, [weakThis = WeakPtr { *this }, promise = WTF::move(promise)] (RequestStorageAccessResult result) mutable {
+ auto hasUserGestureOrNoUserGestureRequired = frame->requestSkipUserActivationCheckForStorageAccess(RegistrableDomain { document->url() }) || UserGestureIndicator::processingUserGesture() ? HasUserGestureOrNoUserGestureRequired::Yes : HasUserGestureOrNoUserGestureRequired::No;
+ page->chrome().client().requestStorageAccess(RegistrableDomain::uncheckedCreateFromHost(protect(document->securityOrigin())->host()), RegistrableDomain::uncheckedCreateFromHost(protect(document->topOrigin())->host()), *frame, m_storageAccessScope, hasUserGestureOrNoUserGestureRequired, [weakThis = WeakPtr { *this }, promise = WTF::move(promise), hasUserGestureOrNoUserGestureRequired] (RequestStorageAccessResult result) mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis)
return;
@@ -252,7 +252,8 @@ void DocumentStorageAccess::requestStorageAccess(Ref&& promise)
shouldPreserveUserGesture = true;
break;
case StorageAccessWasGranted::No:
- shouldPreserveUserGesture = result.promptWasShown == StorageAccessPromptWasShown::No;
+ const bool promptNotShownButMayHaveUserGesture = result.promptWasShown == StorageAccessPromptWasShown::No && hasUserGestureOrNoUserGestureRequired == HasUserGestureOrNoUserGestureRequired::Yes;
+ shouldPreserveUserGesture = promptNotShownButMayHaveUserGesture;
}
Ref document = protectedThis->m_document.get();
@@ -349,7 +350,7 @@ void DocumentStorageAccess::requestStorageAccessQuirk(RegistrableDomain&& reques
auto topFrameDomain = RegistrableDomain(page->mainFrameURL());
RefPtr frame = document->frame();
- page->chrome().client().requestStorageAccess(WTF::move(requestingDomain), WTF::move(topFrameDomain), *frame, m_storageAccessScope, HasOrShouldIgnoreUserGesture::Yes, [weakThis = WeakPtr { *this }, completionHandler = WTF::move(completionHandler)] (RequestStorageAccessResult result) mutable {
+ page->chrome().client().requestStorageAccess(WTF::move(requestingDomain), WTF::move(topFrameDomain), *frame, m_storageAccessScope, HasUserGestureOrNoUserGestureRequired::Yes, [weakThis = WeakPtr { *this }, completionHandler = WTF::move(completionHandler)] (RequestStorageAccessResult result) mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis)
return;
diff --git a/Source/WebCore/dom/DocumentStorageAccess.h b/Source/WebCore/dom/DocumentStorageAccess.h
index 65417557af76..6b46f8105710 100644
--- a/Source/WebCore/dom/DocumentStorageAccess.h
+++ b/Source/WebCore/dom/DocumentStorageAccess.h
@@ -41,7 +41,7 @@ enum class StorageAccessWasGranted : uint8_t { No, Yes, YesWithException };
enum class StorageAccessPromptWasShown : bool { No, Yes };
-enum class HasOrShouldIgnoreUserGesture : bool { No, Yes };
+enum class HasUserGestureOrNoUserGestureRequired : bool { No, Yes };
enum class StorageAccessScope : bool {
PerFrame,
diff --git a/Source/WebCore/history/HistoryItem.h b/Source/WebCore/history/HistoryItem.h
index 835a3d4a199d..dde8deea1cee 100644
--- a/Source/WebCore/history/HistoryItem.h
+++ b/Source/WebCore/history/HistoryItem.h
@@ -227,6 +227,9 @@ class HistoryItem : public RefCountedAndCanMakeWeakPtr {
WEBCORE_EXPORT void setWasCreatedByJSWithoutUserInteraction(bool);
bool wasCreatedByJSWithoutUserInteraction() const { return m_wasCreatedByJSWithoutUserInteraction; }
+ void setIsInitialAboutBlank(bool isInitialAboutBlank) { m_isInitialAboutBlank = isInitialAboutBlank; }
+ bool isInitialAboutBlank() const { return m_isInitialAboutBlank; }
+
#if !LOG_DISABLED
String logString() const;
#endif
@@ -260,6 +263,7 @@ class HistoryItem : public RefCountedAndCanMakeWeakPtr {
bool m_lastVisitWasFailure { false };
bool m_wasRestoredFromSession { false };
bool m_wasCreatedByJSWithoutUserInteraction { false };
+ bool m_isInitialAboutBlank { false };
bool m_shouldRestoreScrollPosition { true };
bool m_isTargetItem { false };
diff --git a/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp b/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp
index 669200ca1b30..143145db0f6d 100644
--- a/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp
+++ b/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp
@@ -153,8 +153,8 @@ void FlexLayout::layout()
auto isOrthogonal = flexContainerIsHorizontal != renderer->writingMode().isHorizontal();
auto borderBox = Layout::BoxGeometry::borderBoxRect(layoutState().geometryForBox(layoutBox));
- renderer->setWidth(LayoutUnit { });
- renderer->setHeight(LayoutUnit { });
+ renderer->setBorderBoxWidth(LayoutUnit { });
+ renderer->setBorderBoxHeight(LayoutUnit { });
// logical here means width and height constraints for the _content_ of the flex items not the flex items' own dimension inside the flex container.
renderer->setOverridingBorderBoxLogicalWidth(isOrthogonal ? borderBox.height() : borderBox.width());
renderer->setOverridingBorderBoxLogicalHeight(isOrthogonal ? borderBox.width() : borderBox.height());
@@ -163,8 +163,8 @@ void FlexLayout::layout()
renderer->layoutIfNeeded();
renderer->clearOverridingSize();
- renderer->setWidth(flexContainerIsHorizontal ? borderBox.width() : borderBox.height());
- renderer->setHeight(flexContainerIsHorizontal ? borderBox.height() : borderBox.width());
+ renderer->setBorderBoxWidth(flexContainerIsHorizontal ? borderBox.width() : borderBox.height());
+ renderer->setBorderBoxHeight(flexContainerIsHorizontal ? borderBox.height() : borderBox.width());
}
};
relayoutFlexItems();
@@ -178,8 +178,8 @@ void FlexLayout::updateRenderers()
auto& flexItemGeometry = layoutState().geometryForBox(layoutBox);
auto borderBox = Layout::BoxGeometry::borderBoxRect(flexItemGeometry);
renderer->setLocation(flexContainerIsHorizontal ? borderBox.topLeft() : borderBox.topLeft().transposedPoint());
- renderer->setWidth(flexContainerIsHorizontal ? borderBox.width() : borderBox.height());
- renderer->setHeight(flexContainerIsHorizontal ? borderBox.height() : borderBox.width());
+ renderer->setBorderBoxWidth(flexContainerIsHorizontal ? borderBox.width() : borderBox.height());
+ renderer->setBorderBoxHeight(flexContainerIsHorizontal ? borderBox.height() : borderBox.width());
renderer->setMarginStart(flexItemGeometry.marginStart());
renderer->setMarginEnd(flexItemGeometry.marginEnd());
diff --git a/Source/WebCore/layout/integration/grid/LayoutIntegrationGridLayout.cpp b/Source/WebCore/layout/integration/grid/LayoutIntegrationGridLayout.cpp
index 4e084be3cb48..721feae82185 100644
--- a/Source/WebCore/layout/integration/grid/LayoutIntegrationGridLayout.cpp
+++ b/Source/WebCore/layout/integration/grid/LayoutIntegrationGridLayout.cpp
@@ -161,8 +161,8 @@ void GridLayout::updateGridItemRenderers()
auto borderBoxRect = Layout::BoxGeometry::borderBoxRect(gridItemGeometry);
renderer->setLocation(contentBoxOffset + borderBoxRect.topLeft());
- renderer->setWidth(borderBoxRect.width());
- renderer->setHeight(borderBoxRect.height());
+ renderer->setBorderBoxWidth(borderBoxRect.width());
+ renderer->setBorderBoxHeight(borderBoxRect.height());
renderer->setMarginBefore(gridItemGeometry.marginBefore());
renderer->setMarginAfter(gridItemGeometry.marginAfter());
@@ -182,9 +182,9 @@ void GridLayout::updateFormattingContextRootRenderer(const Layout::GridLayoutCon
auto& rowSizes = usedTrackSizes.rowSizes;
auto usedRowGutter = Layout::GridFormattingContext::usedGapValue(renderGrid->style().rowGap());
auto blockContentSize = std::reduce(rowSizes.begin(), rowSizes.end()) + Layout::GridLayoutUtils::totalGuttersSize(rowSizes.size(), usedRowGutter);
- renderGrid->setHeight(blockContentSize + renderGrid->borderAndPaddingLogicalHeight());
+ renderGrid->setBorderBoxHeight(blockContentSize + renderGrid->borderAndPaddingLogicalHeight());
} else
- renderGrid->setHeight(layoutConstraints.blockAxis.availableSpace() + renderGrid->borderAndPaddingLogicalHeight());
+ renderGrid->setBorderBoxHeight(layoutConstraints.blockAxis.availableSpace() + renderGrid->borderAndPaddingLogicalHeight());
for (CheckedRef layoutBox : formattingContextBoxes(gridBox()))
orderIteratorPopulator.collectChild(CheckedRef { downcast(*layoutBox->rendererForIntegration()) });
diff --git a/Source/WebCore/loader/HistoryController.cpp b/Source/WebCore/loader/HistoryController.cpp
index 47a8284c3b77..cca0ca00923d 100644
--- a/Source/WebCore/loader/HistoryController.cpp
+++ b/Source/WebCore/loader/HistoryController.cpp
@@ -886,6 +886,8 @@ void HistoryController::initializeItem(HistoryItem& item, RefPtr
item.setShouldOpenExternalURLsPolicy(documentLoader->shouldOpenExternalURLsPolicyToPropagate());
+ item.setIsInitialAboutBlank(documentLoader->isInitialAboutBlank());
+
// Save form state if this is a POST
item.setFormInfoFromRequest(documentLoader->request());
}
diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h
index ed67709d049b..8bd12ba1ab6a 100644
--- a/Source/WebCore/page/ChromeClient.h
+++ b/Source/WebCore/page/ChromeClient.h
@@ -683,7 +683,7 @@ class ChromeClient {
virtual RefPtr createIconForFiles(const Vector& /* filenames */) = 0;
virtual void hasStorageAccess(RegistrableDomain&& /*subFrameDomain*/, RegistrableDomain&& /*topFrameDomain*/, LocalFrame&, CompletionHandler&& completionHandler) { completionHandler(false); }
- virtual void requestStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, LocalFrame&, StorageAccessScope scope, HasOrShouldIgnoreUserGesture, CompletionHandler&& completionHandler) { completionHandler({ StorageAccessWasGranted::No, StorageAccessPromptWasShown::No, scope, WTF::move(topFrameDomain), WTF::move(subFrameDomain) }); }
+ virtual void requestStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, LocalFrame&, StorageAccessScope scope, HasUserGestureOrNoUserGestureRequired, CompletionHandler&& completionHandler) { completionHandler({ StorageAccessWasGranted::No, StorageAccessPromptWasShown::No, scope, WTF::move(topFrameDomain), WTF::move(subFrameDomain) }); }
virtual bool hasPageLevelStorageAccess(const RegistrableDomain& /*topLevelDomain*/, const RegistrableDomain& /*resourceDomain*/) const { return false; }
virtual void setLoginStatus(RegistrableDomain&&, IsLoggedIn, CompletionHandler&&) { }
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
index 9e7c72a7e6ff..5656e3e7cc4a 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
@@ -911,7 +911,7 @@ std::optional ContentSecurityPolicy::getCurrentCodePosition()
void ContentSecurityPolicy::reportViolation(const ContentSecurityPolicyDirective& violatedDirective, const String& blockedURL, const String& consoleMessage, JSC::JSGlobalObject* state, StringView sourceContent) const
{
// FIXME: Extract source file, and position from JSC::ExecState.
- return reportViolation(violatedDirective.nameForReporting().convertToASCIILowercase(), violatedDirective.directiveList(), blockedURL, consoleMessage, String(), sourceContent.left(40), { }, state);
+ return reportViolation(violatedDirective.nameForReporting(), violatedDirective.directiveList(), blockedURL, consoleMessage, String(), sourceContent.left(40), { }, state);
}
void ContentSecurityPolicy::reportViolation(const String& violatedDirective, const ContentSecurityPolicyDirectiveList& violatedDirectiveList, const String& blockedURL, const String& consoleMessage, JSC::JSGlobalObject* state) const
@@ -922,7 +922,7 @@ void ContentSecurityPolicy::reportViolation(const String& violatedDirective, con
void ContentSecurityPolicy::reportViolation(const ContentSecurityPolicyDirective& violatedDirective, const String& blockedURL, const String& consoleMessage, const String& sourceURL, StringView sourceContent, std::optional&& sourcePosition, const URL& preRedirectURL, JSC::JSGlobalObject* state, Element* element) const
{
- return reportViolation(violatedDirective.nameForReporting().convertToASCIILowercase(), violatedDirective.directiveList(), blockedURL, consoleMessage, sourceURL, sourceContent.left(40), WTF::move(sourcePosition), state, preRedirectURL, element);
+ return reportViolation(violatedDirective.nameForReporting(), violatedDirective.directiveList(), blockedURL, consoleMessage, sourceURL, sourceContent.left(40), WTF::move(sourcePosition), state, preRedirectURL, element);
}
void ContentSecurityPolicy::reportViolation(const String& effectiveViolatedDirective, const ContentSecurityPolicyDirectiveList& violatedDirectiveList, const String& blockedURLString, const String& consoleMessage, const String& sourceURL, StringView sourceContent, std::optional&& maybeSourcePosition, JSC::JSGlobalObject* state, const URL& preRedirectURL, Element* element) const
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
index b2ead0efba50..806ff2b00542 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
@@ -487,20 +487,20 @@ void ContentSecurityPolicyDirectiveList::parse(const String& policy, ContentSecu
if (auto directive = parseDirective(std::span { directiveBegin, buffer.position() })) {
ASSERT(!directive->name.isEmpty());
if (policyFrom == ContentSecurityPolicy::PolicyFrom::Inherited) {
- if (equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::upgradeInsecureRequests)
- || equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::sandbox))
+ if (directive->name == ContentSecurityPolicyDirectiveNames::upgradeInsecureRequests
+ || directive->name == ContentSecurityPolicyDirectiveNames::sandbox)
continue;
} else if (policyFrom == ContentSecurityPolicy::PolicyFrom::HTTPEquivMeta) {
- if (equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::sandbox)
- || equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::reportURI)
- || equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::frameAncestors)) {
+ if (directive->name == ContentSecurityPolicyDirectiveNames::sandbox
+ || directive->name == ContentSecurityPolicyDirectiveNames::reportURI
+ || directive->name == ContentSecurityPolicyDirectiveNames::frameAncestors) {
m_policy->reportInvalidDirectiveInHTTPEquivMeta(directive->name);
continue;
}
} else if (policyFrom == ContentSecurityPolicy::PolicyFrom::InheritedForPluginDocument) {
- if (!equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::pluginTypes)
- && !equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::reportURI)
- && !equalIgnoringASCIICase(directive->name, ContentSecurityPolicyDirectiveNames::reportTo))
+ if (directive->name != ContentSecurityPolicyDirectiveNames::pluginTypes
+ && directive->name != ContentSecurityPolicyDirectiveNames::reportURI
+ && directive->name != ContentSecurityPolicyDirectiveNames::reportTo)
continue;
}
addDirective(WTF::move(*directive));
@@ -535,7 +535,8 @@ template auto ContentSecurityPolicyDirectiveList::parseD
return std::nullopt;
}
- String name { nameBegin.first(buffer.position() - nameBegin.data()) };
+ // Lowercase the directive name eagerly so downstream code can use case-sensitive comparisons.
+ String name = StringView { nameBegin.first(buffer.position() - nameBegin.data()) }.convertToASCIILowercase();
if (buffer.atEnd())
return ParsedDirective { WTF::move(name), { } };
@@ -689,75 +690,75 @@ void ContentSecurityPolicyDirectiveList::addDirective(ParsedDirective&& directiv
{
ASSERT(!directive.name.isEmpty());
- if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::defaultSrc)) {
+ if (directive.name == ContentSecurityPolicyDirectiveNames::defaultSrc) {
setCSPDirective(WTF::move(directive), m_defaultSrc);
m_policy->addHashAlgorithmsForInlineScripts(m_defaultSrc->hashAlgorithmsUsed());
m_policy->addHashAlgorithmsForInlineStylesheets(m_defaultSrc->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::scriptSrc)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::scriptSrc) {
setCSPDirective(WTF::move(directive), m_scriptSrc);
m_policy->addHashAlgorithmsForInlineScripts(m_scriptSrc->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::scriptSrcElem)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::scriptSrcElem) {
setCSPDirective(WTF::move(directive), m_scriptSrcElem);
m_policy->addHashAlgorithmsForInlineScripts(m_scriptSrcElem->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::scriptSrcAttr)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::scriptSrcAttr) {
setCSPDirective(WTF::move(directive), m_scriptSrcAttr);
m_policy->addHashAlgorithmsForInlineScripts(m_scriptSrcAttr->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::styleSrc)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::styleSrc) {
setCSPDirective(WTF::move(directive), m_styleSrc);
m_policy->addHashAlgorithmsForInlineStylesheets(m_styleSrc->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::styleSrcElem)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::styleSrcElem) {
setCSPDirective(WTF::move(directive), m_styleSrcElem);
m_policy->addHashAlgorithmsForInlineStylesheets(m_styleSrcElem->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::styleSrcAttr)) {
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::styleSrcAttr) {
setCSPDirective(WTF::move(directive), m_styleSrcAttr);
m_policy->addHashAlgorithmsForInlineStylesheets(m_styleSrcAttr->hashAlgorithmsUsed());
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::objectSrc))
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::objectSrc)
setCSPDirective(WTF::move(directive), m_objectSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::workerSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::workerSrc)
setCSPDirective(WTF::move(directive), m_workerSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::frameSrc)) {
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::frameSrc) {
// FIXME: Log to console "The frame-src directive is deprecated. Use the child-src directive instead."
// See .
setCSPDirective(WTF::move(directive), m_frameSrc);
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::imgSrc))
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::imgSrc)
setCSPDirective(WTF::move(directive), m_imgSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::fontSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::fontSrc)
setCSPDirective(WTF::move(directive), m_fontSrc);
#if ENABLE(APPLICATION_MANIFEST)
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::manifestSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::manifestSrc)
setCSPDirective(WTF::move(directive), m_manifestSrc);
#endif
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::mediaSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::mediaSrc)
setCSPDirective(WTF::move(directive), m_mediaSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::connectSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::connectSrc)
setCSPDirective(WTF::move(directive), m_connectSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::childSrc))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::childSrc)
setCSPDirective(WTF::move(directive), m_childSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::formAction))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::formAction)
setCSPDirective(WTF::move(directive), m_formAction);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::baseURI))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::baseURI)
setCSPDirective(WTF::move(directive), m_baseURI);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::frameAncestors))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::frameAncestors)
setCSPDirective(WTF::move(directive), m_frameAncestors);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::pluginTypes)) {
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::pluginTypes) {
auto name = directive.name;
setCSPDirective(WTF::move(directive), m_pluginTypes);
m_policy->reportDeprecatedDirectiveToConsole(name);
- } else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::prefetchSrc))
+ } else if (directive.name == ContentSecurityPolicyDirectiveNames::prefetchSrc)
setCSPDirective(WTF::move(directive), m_prefetchSrc);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::sandbox))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::sandbox)
applySandboxPolicy(WTF::move(directive));
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::reportTo))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::reportTo)
parseReportTo(WTF::move(directive));
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::reportURI))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::reportURI)
parseReportURI(WTF::move(directive));
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::upgradeInsecureRequests))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::upgradeInsecureRequests)
setUpgradeInsecureRequests(WTF::move(directive));
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::blockAllMixedContent))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::blockAllMixedContent)
setBlockAllMixedContentEnabled(WTF::move(directive));
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::trustedTypes))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::trustedTypes)
setCSPDirective(WTF::move(directive), m_trustedTypes);
- else if (equalIgnoringASCIICase(directive.name, ContentSecurityPolicyDirectiveNames::requireTrustedTypesFor))
+ else if (directive.name == ContentSecurityPolicyDirectiveNames::requireTrustedTypesFor)
parseRequireTrustedTypesFor(WTF::move(directive));
else
m_policy->reportUnsupportedDirective(WTF::move(directive.name));
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
index 142083d1e8c1..2f84719ec286 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
@@ -43,6 +43,7 @@ namespace WebCore {
static bool NODELETE isCSPDirectiveName(StringView name)
{
+ // Called with a source-expression token, not a parsed directive name, so it is not lowercased.
return equalIgnoringASCIICase(name, ContentSecurityPolicyDirectiveNames::baseURI)
|| equalIgnoringASCIICase(name, ContentSecurityPolicyDirectiveNames::connectSrc)
|| equalIgnoringASCIICase(name, ContentSecurityPolicyDirectiveNames::defaultSrc)
@@ -120,9 +121,9 @@ bool ContentSecurityPolicySourceList::isProtocolAllowedByStar(const URL& url) co
bool isAllowed = url.protocolIsInHTTPFamily() || url.protocolIs("ws"_s) || url.protocolIs("wss"_s) || url.protocolIs(m_policy->selfProtocol());
// Also not allowed by the Content Security Policy Level 3 spec., we allow a data URL to match
// "img-src *" and either a data URL or blob URL to match "media-src *" for web compatibility.
- if (equalIgnoringASCIICase(m_directiveName, ContentSecurityPolicyDirectiveNames::imgSrc))
+ if (m_directiveName == ContentSecurityPolicyDirectiveNames::imgSrc)
isAllowed |= url.protocolIsData();
- else if (equalIgnoringASCIICase(m_directiveName, ContentSecurityPolicyDirectiveNames::mediaSrc))
+ else if (m_directiveName == ContentSecurityPolicyDirectiveNames::mediaSrc)
isAllowed |= url.protocolIsData() || url.protocolIsBlob();
return isAllowed;
}
diff --git a/Source/WebCore/platform/audio/cocoa/AudioEncoderCocoa.cpp b/Source/WebCore/platform/audio/cocoa/AudioEncoderCocoa.cpp
index f8c04443535b..fa49a0e92d4e 100644
--- a/Source/WebCore/platform/audio/cocoa/AudioEncoderCocoa.cpp
+++ b/Source/WebCore/platform/audio/cocoa/AudioEncoderCocoa.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 Apple Inc. All rights reserved.
+ * Copyright (C) 2024-2026 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -314,7 +314,7 @@ Ref InternalAudioEncoderCocoa::encode(AudioEncoder:
if (*asbd != m_inputDescription) {
if (RefPtr converter = std::exchange(m_converter, { }))
- converter->finish();
+ converter->finish()->whenSettled(queueSingleton(), [protectedThis = Ref { *this }] { });
m_inputDescription = *asbd;
AudioSampleBufferConverter::Options options = {
diff --git a/Source/WebCore/platform/audio/ios/MediaDeviceRoute.h b/Source/WebCore/platform/audio/ios/MediaDeviceRoute.h
index e08f7c16faa1..639b033f5272 100644
--- a/Source/WebCore/platform/audio/ios/MediaDeviceRoute.h
+++ b/Source/WebCore/platform/audio/ios/MediaDeviceRoute.h
@@ -39,7 +39,7 @@
#include
#include
-OBJC_CLASS WebMediaSourceObserver;
+OBJC_CLASS WebPlaybackControlObserver;
namespace WebCore {
@@ -91,9 +91,9 @@ class MediaDeviceRouteClient : public AbstractRefCountedAndCanMakeWeakPtr playbackError() const;
+ std::optional error() const;
Vector audioOptions() const;
- MediaTime currentPlaybackPosition() const;
+ MediaTime playbackPosition() const;
bool playing() const;
float playbackSpeed() const;
float scanSpeed() const;
bool muted() const;
float volume() const;
- void setCurrentPlaybackPosition(MediaTime);
+ void setPlaybackPosition(MediaTime);
void setPlaying(bool);
void setPlaybackSpeed(float);
void setScanSpeed(float);
@@ -141,7 +141,7 @@ class MediaDeviceRoute final : public RefCountedAndCanMakeWeakPtr m_platformRoute;
- RetainPtr m_mediaSourceObserver;
+ RetainPtr m_playbackControlObserver;
WeakPtr m_client;
#if HAVE(AVROUTING_FRAMEWORK)
RetainPtr m_routeSession;
diff --git a/Source/WebCore/platform/audio/ios/MediaDeviceRoute.mm b/Source/WebCore/platform/audio/ios/MediaDeviceRoute.mm
index 13230fa39b2d..16bab672f212 100644
--- a/Source/WebCore/platform/audio/ios/MediaDeviceRoute.mm
+++ b/Source/WebCore/platform/audio/ios/MediaDeviceRoute.mm
@@ -36,14 +36,16 @@
#import
-#define FOR_EACH_COMMON_READONLY_KEY_PATH(Macro) \
+#define FOR_EACH_READONLY_KEY_PATH(Macro) \
Macro(timeRange, TimeRange, MediaTimeRange) \
Macro(ready, Ready, bool) \
Macro(buffering, Buffering, bool) \
Macro(audioOptions, AudioOptions, Vector) \
+ Macro(error, Error, std::optional) \
+ Macro(playbackPosition, PlaybackPosition, MediaTime) \
\
-#define FOR_EACH_COMMON_READWRITE_KEY_PATH(Macro) \
+#define FOR_EACH_READWRITE_KEY_PATH(Macro) \
Macro(playing, Playing, bool) \
Macro(playbackSpeed, PlaybackSpeed, float) \
Macro(scanSpeed, ScanSpeed, float) \
@@ -51,43 +53,16 @@
Macro(volume, Volume, float) \
\
-#define FOR_EACH_COMMON_KEY_PATH(Macro) \
- FOR_EACH_COMMON_READONLY_KEY_PATH(Macro) \
- FOR_EACH_COMMON_READWRITE_KEY_PATH(Macro) \
+#define FOR_EACH_KEY_PATH(Macro) \
+ FOR_EACH_READONLY_KEY_PATH(Macro) \
+ FOR_EACH_READWRITE_KEY_PATH(Macro) \
\
-#define FOR_EACH_MEDIA_SOURCE_READONLY_KEY_PATH(Macro) \
- FOR_EACH_COMMON_READONLY_KEY_PATH(Macro) \
- Macro(playbackError, PlaybackError, std::optional) \
-\
-
-#define FOR_EACH_MEDIA_SOURCE_READWRITE_KEY_PATH(Macro) \
- FOR_EACH_COMMON_READWRITE_KEY_PATH(Macro) \
- Macro(currentPlaybackPosition, CurrentPlaybackPosition, MediaTime) \
-\
-
-#define FOR_EACH_MEDIA_SOURCE_KEY_PATH(Macro) \
- FOR_EACH_MEDIA_SOURCE_READONLY_KEY_PATH(Macro) \
- FOR_EACH_MEDIA_SOURCE_READWRITE_KEY_PATH(Macro) \
-\
-
-#define FOR_EACH_PLAYBACK_CONTROL_KEY_PATH(Macro) \
- FOR_EACH_COMMON_KEY_PATH(Macro) \
-\
-
-#define ADD_MEDIA_SOURCE_OBSERVER(KeyPath, SetterSuffix, Type) \
- [_mediaSource addObserver:self forKeyPath:@#KeyPath options:NSKeyValueObservingOptionInitial context:WebMediaSourceObserverContext]; \
-\
-
-#define REMOVE_MEDIA_SOURCE_OBSERVER(KeyPath, SetterSuffix, Type) \
- [_mediaSource removeObserver:self forKeyPath:@#KeyPath context:WebMediaSourceObserverContext]; \
-\
-
-#define ADD_PLAYBACK_CONTROL_OBSERVER(KeyPath, SetterSuffix, Type) \
+#define ADD_OBSERVER(KeyPath, SetterSuffix, Type) \
[_playbackControl addObserver:self forKeyPath:@#KeyPath options:NSKeyValueObservingOptionInitial context:WebPlaybackControlObserverContext]; \
\
-#define REMOVE_PLAYBACK_CONTROL_OBSERVER(KeyPath, SetterSuffix, Type) \
+#define REMOVE_OBSERVER(KeyPath, SetterSuffix, Type) \
[_playbackControl removeObserver:self forKeyPath:@#KeyPath context:WebPlaybackControlObserverContext]; \
\
@@ -108,37 +83,30 @@
#define DEFINE_GETTER(KeyPath, SetterSuffix, Type) \
Type MediaDeviceRoute::KeyPath() const \
{ \
- if (RetainPtr playbackControl = [m_mediaSourceObserver playbackControl]) \
- return convert(playbackControl.get().KeyPath); \
- return convert([m_mediaSourceObserver mediaSource].KeyPath); \
+ return convert([m_playbackControlObserver playbackControl].KeyPath); \
} \
\
#define DEFINE_SETTER(KeyPath, SetterSuffix, Type) \
void MediaDeviceRoute::set##SetterSuffix(Type KeyPath) \
{ \
- if (RetainPtr playbackControl = [m_mediaSourceObserver playbackControl]) \
- return [playbackControl set##SetterSuffix:convert(WTF::move(KeyPath))]; \
- [[m_mediaSourceObserver mediaSource] set##SetterSuffix:convert(WTF::move(KeyPath))]; \
+ [[m_playbackControlObserver playbackControl] set##SetterSuffix:convert(WTF::move(KeyPath))]; \
} \
\
NS_ASSUME_NONNULL_BEGIN
-static void* WebMediaSourceObserverContext = &WebMediaSourceObserverContext;
static void* WebPlaybackControlObserverContext = &WebPlaybackControlObserverContext;
-@interface WebMediaSourceObserver : NSObject
+@interface WebPlaybackControlObserver : NSObject
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithRoute:(WebCore::MediaDeviceRoute&)route NS_DESIGNATED_INITIALIZER;
-@property (nonatomic, nullable, strong) AVMediaSource *mediaSource;
@property (nonatomic, nullable, strong) AVPlaybackControl *playbackControl;
@end
-@implementation WebMediaSourceObserver {
+@implementation WebPlaybackControlObserver {
WeakPtr _route;
- RetainPtr _mediaSource;
RetainPtr _playbackControl;
}
@@ -151,23 +119,6 @@ - (instancetype)initWithRoute:(WebCore::MediaDeviceRoute&)route
return self;
}
-- (AVMediaSource * _Nullable)mediaSource
-{
- return _mediaSource.get();
-}
-
-- (void)setMediaSource:(AVMediaSource * _Nullable)mediaSource
-{
- if (mediaSource)
- self.playbackControl = nil;
-
- FOR_EACH_MEDIA_SOURCE_KEY_PATH(REMOVE_MEDIA_SOURCE_OBSERVER)
-
- _mediaSource = mediaSource;
-
- FOR_EACH_MEDIA_SOURCE_KEY_PATH(ADD_MEDIA_SOURCE_OBSERVER)
-}
-
- (AVPlaybackControl * _Nullable)playbackControl
{
return _playbackControl.get();
@@ -175,60 +126,29 @@ - (AVPlaybackControl * _Nullable)playbackControl
- (void)setPlaybackControl:(AVPlaybackControl * _Nullable)playbackControl
{
- if (playbackControl)
- self.mediaSource = nil;
-
- FOR_EACH_PLAYBACK_CONTROL_KEY_PATH(REMOVE_PLAYBACK_CONTROL_OBSERVER)
- REMOVE_PLAYBACK_CONTROL_OBSERVER(error, Error, std::optional)
- REMOVE_PLAYBACK_CONTROL_OBSERVER(playbackPosition, PlaybackPosition, AVPlaybackUserInterfacePlaybackPosition *)
+ FOR_EACH_KEY_PATH(REMOVE_OBSERVER)
_playbackControl = playbackControl;
- FOR_EACH_PLAYBACK_CONTROL_KEY_PATH(ADD_PLAYBACK_CONTROL_OBSERVER)
- ADD_PLAYBACK_CONTROL_OBSERVER(error, Error, std::optional)
- ADD_PLAYBACK_CONTROL_OBSERVER(playbackPosition, PlaybackPosition, AVPlaybackUserInterfacePlaybackPosition *)
+ FOR_EACH_KEY_PATH(ADD_OBSERVER)
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void*)context
{
- if (context != WebMediaSourceObserverContext && context != WebPlaybackControlObserverContext) {
+ if (context != WebPlaybackControlObserverContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
dispatch_async(mainDispatchQueueSingleton(), ^{
- if (context == WebMediaSourceObserverContext) {
- FOR_EACH_MEDIA_SOURCE_KEY_PATH(OBSERVE_VALUE)
- ASSERT_NOT_REACHED();
- return;
- }
-
- if ([keyPath isEqualToString:@"error"]) {
- if (RefPtr route = _route.get()) {
- if (RefPtr client = route->client())
- client->playbackErrorDidChange(*route);
- }
- return;
- }
- if ([keyPath isEqualToString:@"playbackPosition"]) {
- if (RefPtr route = _route.get()) {
- if (RefPtr client = route->client())
- client->currentPlaybackPositionDidChange(*route);
- }
- return;
- }
-
- FOR_EACH_PLAYBACK_CONTROL_KEY_PATH(OBSERVE_VALUE)
+ FOR_EACH_KEY_PATH(OBSERVE_VALUE)
ASSERT_NOT_REACHED();
});
}
- (void)dealloc
{
- FOR_EACH_MEDIA_SOURCE_KEY_PATH(REMOVE_MEDIA_SOURCE_OBSERVER)
- FOR_EACH_PLAYBACK_CONTROL_KEY_PATH(REMOVE_PLAYBACK_CONTROL_OBSERVER)
- REMOVE_PLAYBACK_CONTROL_OBSERVER(error, Error, std::optional)
- REMOVE_PLAYBACK_CONTROL_OBSERVER(playbackPosition, PlaybackPosition, AVPlaybackUserInterfacePlaybackPosition *)
+ FOR_EACH_KEY_PATH(REMOVE_OBSERVER)
[super dealloc];
}
@@ -260,6 +180,11 @@ static MediaTime convert(CMTime time)
return PAL::toMediaTime(time);
}
+static MediaTime convert(AVPlaybackUserInterfacePlaybackPosition *playbackPosition)
+{
+ return convert(playbackPosition.position);
+}
+
static MediaTimeRange convert(CMTimeRange timeRange)
{
MediaTime start = PAL::toMediaTime(timeRange.start);
@@ -301,7 +226,7 @@ static MediaTimeRange convert(CMTimeRange timeRange)
MediaDeviceRoute::MediaDeviceRoute(WebMediaDevicePlatformRoute *platformRoute)
: m_identifier { WTF::UUID::createVersion4() }
, m_platformRoute { platformRoute }
- , m_mediaSourceObserver { adoptNS([[WebMediaSourceObserver alloc] initWithRoute:*this]) }
+ , m_playbackControlObserver { adoptNS([[WebPlaybackControlObserver alloc] initWithRoute:*this]) }
{
}
@@ -315,29 +240,10 @@ static MediaTimeRange convert(CMTimeRange timeRange)
return m_platformRoute.get();
}
-std::optional MediaDeviceRoute::playbackError() const
+void MediaDeviceRoute::setPlaybackPosition(MediaTime playbackPosition)
{
- if (RetainPtr playbackControl = [m_mediaSourceObserver playbackControl])
- return convert(playbackControl.get().error);
- return convert([m_mediaSourceObserver mediaSource].playbackError);
-}
-
-MediaTime MediaDeviceRoute::currentPlaybackPosition() const
-{
- if (RetainPtr playbackControl = [m_mediaSourceObserver playbackControl])
- return convert(playbackControl.get().playbackPosition.position);
- return convert([m_mediaSourceObserver mediaSource].currentPlaybackPosition);
-}
-
-void MediaDeviceRoute::setCurrentPlaybackPosition(MediaTime currentPlaybackPosition)
-{
- if (RetainPtr playbackControl = [m_mediaSourceObserver playbackControl]) {
- // FIXME: We should introduce a proper seek-with-tolerance function on MediaDeviceRoute rather than assuming a zero tolerance here.
- [playbackControl seekToPosition:convert(WTF::move(currentPlaybackPosition)) tolerance:PAL::kCMTimeZero];
- return;
- }
-
- [m_mediaSourceObserver mediaSource].currentPlaybackPosition = convert(WTF::move(currentPlaybackPosition));
+ // FIXME: We should introduce a proper seek-with-tolerance function on MediaDeviceRoute rather than assuming a zero tolerance here.
+ [[m_playbackControlObserver playbackControl] seekToPosition:convert(WTF::move(playbackPosition)) tolerance:PAL::kCMTimeZero];
}
MediaDeviceRoute::~MediaDeviceRoute()
@@ -347,22 +253,16 @@ static MediaTimeRange convert(CMTimeRange timeRange)
#endif
}
-FOR_EACH_COMMON_KEY_PATH(DEFINE_GETTER)
-FOR_EACH_COMMON_READWRITE_KEY_PATH(DEFINE_SETTER)
+FOR_EACH_KEY_PATH(DEFINE_GETTER)
+FOR_EACH_READWRITE_KEY_PATH(DEFINE_SETTER)
} // namespace WebCore
-#undef FOR_EACH_COMMON_READONLY_KEY_PATH
-#undef FOR_EACH_COMMON_READWRITE_KEY_PATH
-#undef FOR_EACH_COMMON_KEY_PATH
-#undef FOR_EACH_MEDIA_SOURCE_READONLY_KEY_PATH
-#undef FOR_EACH_MEDIA_SOURCE_READWRITE_KEY_PATH
-#undef FOR_EACH_MEDIA_SOURCE_KEY_PATH
-#undef FOR_EACH_PLAYBACK_CONTROL_KEY_PATH
-#undef ADD_MEDIA_SOURCE_OBSERVER
-#undef REMOVE_MEDIA_SOURCE_OBSERVER
-#undef ADD_PLAYBACK_CONTROL_OBSERVER
-#undef REMOVE_PLAYBACK_CONTROL_OBSERVER
+#undef FOR_EACH_READONLY_KEY_PATH
+#undef FOR_EACH_READWRITE_KEY_PATH
+#undef FOR_EACH_KEY_PATH
+#undef ADD_OBSERVER
+#undef REMOVE_OBSERVER
#undef OBSERVE_VALUE
#undef DEFINE_GETTER
#undef DEFINE_SETTER
diff --git a/Source/WebCore/platform/graphics/BitmapImageSource.cpp b/Source/WebCore/platform/graphics/BitmapImageSource.cpp
index 276ac65b83eb..e4fd04575808 100644
--- a/Source/WebCore/platform/graphics/BitmapImageSource.cpp
+++ b/Source/WebCore/platform/graphics/BitmapImageSource.cpp
@@ -513,7 +513,7 @@ void BitmapImageSource::cacheNativeImageAtIndex(unsigned index, SubsamplingLevel
destination.headroom = nativeImage->headroom();
cacheMetadataAtIndex(index, subsamplingLevel, options);
- decodedSizeIncreased(frame.sizeInBytes());
+ decodedSizeIncreased(destination.sizeInBytes());
}
const ImageFrame& BitmapImageSource::frameAtIndex(unsigned index) const
diff --git a/Source/WebCore/platform/graphics/DestinationColorSpace.cpp b/Source/WebCore/platform/graphics/DestinationColorSpace.cpp
index c74fb6fe6dc5..f99b66ec4130 100644
--- a/Source/WebCore/platform/graphics/DestinationColorSpace.cpp
+++ b/Source/WebCore/platform/graphics/DestinationColorSpace.cpp
@@ -208,6 +208,16 @@ bool DestinationColorSpace::supportsOutput() const
#endif
}
+bool DestinationColorSpace::usesRGBColorModel() const
+{
+#if USE(CG)
+ // Avoid refing color space here as this is performance-sensitive.
+ SUPPRESS_UNRETAINED_ARG return CGColorSpaceGetModel(platformColorSpace()) == kCGColorSpaceModelRGB;
+#else
+ return true;
+#endif
+}
+
bool DestinationColorSpace::usesExtendedRange() const
{
#if USE(CG)
diff --git a/Source/WebCore/platform/graphics/DestinationColorSpace.h b/Source/WebCore/platform/graphics/DestinationColorSpace.h
index d567d73f15b5..eb08a70b37c2 100644
--- a/Source/WebCore/platform/graphics/DestinationColorSpace.h
+++ b/Source/WebCore/platform/graphics/DestinationColorSpace.h
@@ -73,6 +73,7 @@ class DestinationColorSpace {
WEBCORE_EXPORT bool supportsOutput() const;
+ WEBCORE_EXPORT bool usesRGBColorModel() const;
WEBCORE_EXPORT bool usesExtendedRange() const;
bool usesITUR_2100TF() const;
diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.cpp b/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.cpp
index 115d8254dc3f..b4b547813277 100644
--- a/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.cpp
+++ b/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.cpp
@@ -280,7 +280,7 @@ void MediaPlayerPrivateWirelessPlayback::seekToTarget(const SeekTarget& seekTarg
return;
ALWAYS_LOG(LOGIDENTIFIER, seekTarget);
- route->setCurrentPlaybackPosition(seekTarget.time);
+ route->setPlaybackPosition(seekTarget.time);
}
bool MediaPlayerPrivateWirelessPlayback::paused() const
@@ -430,12 +430,12 @@ void MediaPlayerPrivateWirelessPlayback::readyDidChange(MediaDeviceRoute& route)
setReadyState(MediaPlayerReadyState::HaveEnoughData);
}
-void MediaPlayerPrivateWirelessPlayback::playbackErrorDidChange(MediaDeviceRoute& route)
+void MediaPlayerPrivateWirelessPlayback::errorDidChange(MediaDeviceRoute& route)
{
ASSERT(&route == this->route());
- ALWAYS_LOG(LOGIDENTIFIER, !!route.playbackError());
+ ALWAYS_LOG(LOGIDENTIFIER, !!route.error());
- if (route.playbackError())
+ if (route.error())
setNetworkState(route.ready() ? MediaPlayer::NetworkState::DecodeError : MediaPlayer::NetworkState::FormatError);
}
@@ -448,14 +448,14 @@ void MediaPlayerPrivateWirelessPlayback::audioOptionsDidChange(MediaDeviceRoute&
player->characteristicChanged();
}
-void MediaPlayerPrivateWirelessPlayback::currentPlaybackPositionDidChange(MediaDeviceRoute& route)
+void MediaPlayerPrivateWirelessPlayback::playbackPositionDidChange(MediaDeviceRoute& route)
{
ASSERT(&route == this->route());
- auto currentPlaybackPosition = route.currentPlaybackPosition();
- ALWAYS_LOG(LOGIDENTIFIER, currentPlaybackPosition);
+ auto playbackPosition = route.playbackPosition();
+ ALWAYS_LOG(LOGIDENTIFIER, playbackPosition);
- updateTimebaseTimeAndRate(currentPlaybackPosition, route.playing() ? route.playbackSpeed() : 0);
+ updateTimebaseTimeAndRate(playbackPosition, route.playing() ? route.playbackSpeed() : 0);
auto currentTime = this->currentTime();
@@ -492,7 +492,7 @@ CMTimebaseRef MediaPlayerPrivateWirelessPlayback::ensureTimebase()
dispatch_activate(m_timerSource.get());
if (RefPtr route = this->route())
- updateTimebaseTimeAndRate(route->currentPlaybackPosition() ?: MediaTime::zeroTime(), route->playing() ? route->playbackSpeed() : 0);
+ updateTimebaseTimeAndRate(route->playbackPosition() ?: MediaTime::zeroTime(), route->playing() ? route->playbackSpeed() : 0);
return m_timebase.get();
}
diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.h b/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.h
index 8f599b6d1d01..89d553fa6f03 100644
--- a/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.h
+++ b/Source/WebCore/platform/graphics/MediaPlayerPrivateWirelessPlayback.h
@@ -129,9 +129,9 @@ class MediaPlayerPrivateWirelessPlayback final
// MediaDeviceRouteClient
void timeRangeDidChange(MediaDeviceRoute&) final;
void readyDidChange(MediaDeviceRoute&) final;
- void playbackErrorDidChange(MediaDeviceRoute&) final;
+ void errorDidChange(MediaDeviceRoute&) final;
void audioOptionsDidChange(MediaDeviceRoute&) final;
- void currentPlaybackPositionDidChange(MediaDeviceRoute&) final;
+ void playbackPositionDidChange(MediaDeviceRoute&) final;
CMTimebaseRef ensureTimebase();
void destroyTimebase();
diff --git a/Source/WebCore/platform/graphics/MediaSourcePrivate.cpp b/Source/WebCore/platform/graphics/MediaSourcePrivate.cpp
index 44e79f12968e..e13cf3229600 100644
--- a/Source/WebCore/platform/graphics/MediaSourcePrivate.cpp
+++ b/Source/WebCore/platform/graphics/MediaSourcePrivate.cpp
@@ -58,7 +58,7 @@ bool MediaSourcePrivate::hasFutureTime(const MediaTime& currentTime, const Media
auto ranges = buffered();
MediaTime nearest = ranges.nearest(currentTime);
- if (abs(nearest - currentTime) > timeFudgeFactor())
+ if (abs(nearest - currentTime) > gapToleranceAtTime(currentTime))
return false;
size_t found = ranges.find(nearest);
@@ -94,12 +94,20 @@ bool MediaSourcePrivate::hasBufferedTime(const MediaTime& time) const
if (!ranges.length())
return false;
- return abs(ranges.nearest(time) - time) <= timeFudgeFactor();
+ return abs(ranges.nearest(time) - time) <= gapToleranceAtTime(time);
}
bool MediaSourcePrivate::hasCurrentTime() const
{
- return hasBufferedTime(currentTime());
+ auto time = currentTime();
+ if (hasBufferedTime(time))
+ return true;
+ // Per MSE 2 §presentation-start-time: the user agent may treat a current
+ // playback position at or after time 0 and before the first buffered
+ // range as covered, provided the first range starts within a small
+ // window after presentation start. Affects readyState only;
+ // HTMLMediaElement.buffered reported to JS is unchanged.
+ return m_readyState.load() != MediaSourceReadyState::Closed && isWithinStartGapAllowance(time);
}
bool MediaSourcePrivate::isBuffered(const PlatformTimeRanges& ranges) const
@@ -107,7 +115,9 @@ bool MediaSourcePrivate::isBuffered(const PlatformTimeRanges& ranges) const
if (m_readyState.load() == MediaSourceReadyState::Closed)
return false;
- return buffered().containWithEpsilon(ranges, timeFudgeFactor());
+ return buffered().containWithEpsilon(ranges, [&](const MediaTime& time) {
+ return gapToleranceAtTime(time);
+ });
}
MediaSourcePrivate::MediaSourcePrivate(MediaSourcePrivateClient& client)
@@ -173,7 +183,6 @@ void MediaSourcePrivate::cancelPendingWaitForTarget()
protectedThis->m_pendingSeekTarget.reset();
}
protectedThis->m_waitForTargetPromise.reset();
- protectedThis->m_reenqueuePending = false;
});
}
@@ -376,6 +385,20 @@ void MediaSourcePrivate::updateBufferedRanges()
});
auto newBuffered = MediaSourcePrivate::computeBufferedRanges(activeRanges, ended);
+
+ // Aggregate audio-only buffered ranges across active SourceBuffers so
+ // the canplaythrough gap policy can ask "does any audio bridge this
+ // gap?" — see MediaSourcePrivate::gapToleranceAtTime.
+ PlatformTimeRanges newAudioBuffered;
+ for (RefPtr sourceBuffer : m_activeSourceBuffers) {
+ if (sourceBuffer)
+ newAudioBuffered.unionWith(sourceBuffer->audioBufferedRanges());
+ }
+ {
+ Locker locker { m_lock };
+ m_audioBuffered = WTF::move(newAudioBuffered);
+ }
+
if (isBufferedEqual(newBuffered))
return;
bufferedChanged(WTF::move(newBuffered));
@@ -601,6 +624,83 @@ void MediaSourcePrivate::shutdown()
{
}
+MediaTime MediaSourcePrivate::nextStallTime(const MediaTime& currentTime) const
+{
+ auto stallAtTime = duration();
+ auto ranges = buffered();
+ size_t index = ranges.find(currentTime);
+ if (index == notFound)
+ return stallAtTime;
+
+ // Find the next gap (or end of media).
+ auto remaining = ranges.span().subspan(index);
+ for (size_t i = 0; i < remaining.size(); i++) {
+ auto rangeEnd = remaining[i].end;
+ if (i + 1 < remaining.size()) {
+ if (remaining[i + 1].start - rangeEnd > gapToleranceAtTime(rangeEnd)) {
+ stallAtTime = rangeEnd;
+ break;
+ }
+ continue;
+ }
+ // Final range.
+ if (rangeEnd > currentTime)
+ stallAtTime = rangeEnd;
+ break;
+ }
+ return stallAtTime;
+}
+
+MediaTime MediaSourcePrivate::gapToleranceAtTime(const MediaTime& time, std::optional excluded) const
+{
+ // Start-of-stream allowance: gap is before the first buffered range and
+ // close to presentation start time.
+ if (isWithinStartGapAllowance(time))
+ return startGapAllowance();
+
+ // Mid-stream: widen to audioCoveredGapTolerance() when an audio track
+ // bridges the gap, otherwise midStreamGapTolerance().
+ //
+ // When called with an `excluded` track the caller is on the dispatcher
+ // (TrackBuffer's IsCoveredByOtherTracks lambda runs from
+ // SourceBufferPrivate methods that assert dispatcher); walk
+ // m_activeSourceBuffers directly.
+ if (excluded) {
+ assertIsCurrent(m_dispatcher.get());
+ for (RefPtr sourceBuffer : m_activeSourceBuffers) {
+ if (sourceBuffer && sourceBuffer->isAudioBufferedAt(time, *excluded))
+ return audioCoveredGapTolerance();
+ }
+ return midStreamGapTolerance();
+ }
+
+ // Other callers read the cached audio union.
+ Locker locker { m_lock };
+ return m_audioBuffered.contain(time) ? audioCoveredGapTolerance() : midStreamGapTolerance();
+}
+
+
+
+bool MediaSourcePrivate::isWithinStartGapAllowance(const MediaTime& time) const
+{
+ // MSE 2 §presentation-start-time:
+ // "For the purposes of determining if HTMLMediaElement's buffered contains
+ // a TimeRanges that includes the current playback position, implementations
+ // MAY choose to allow a current playback position at or after presentation
+ // start time and before the first TimeRanges to play the first TimeRanges
+ // if that TimeRanges starts within a reasonably short time, like 1 second,
+ // after presentation start time. This allowance accommodates the reality
+ // that muxed streams commonly do not begin all tracks precisely at
+ // presentation start time. Implementations MUST report the actual buffered
+ // range, regardless of this allowance."
+ if (time < MediaTime::zeroTime() || time >= startGapAllowance())
+ return false;
+ auto ranges = buffered();
+ if (!ranges.length())
+ return false;
+ return ranges.start(0) <= startGapAllowance() && time < ranges.start(0);
+}
+
} // namespace WebCore
#endif
diff --git a/Source/WebCore/platform/graphics/MediaSourcePrivate.h b/Source/WebCore/platform/graphics/MediaSourcePrivate.h
index 5211a885cc9f..46ea2b792c79 100644
--- a/Source/WebCore/platform/graphics/MediaSourcePrivate.h
+++ b/Source/WebCore/platform/graphics/MediaSourcePrivate.h
@@ -127,8 +127,33 @@ class WEBCORE_EXPORT MediaSourcePrivate
void clearReenqueuePending() { m_reenqueuePending = false; }
void cancelPendingWaitForTarget();
- void setTimeFudgeFactor(const MediaTime& fudgeFactor) { m_timeFudgeFactor = fudgeFactor; }
- MediaTime timeFudgeFactor() const { return m_timeFudgeFactor; }
+ // Single source of truth for canplaythrough / gap-handling policy across
+ // the MSE pipeline. All values are durations.
+ // - startGapAllowance: per MSE 2 §presentation-start-time, allow up to
+ // 1s gap from time 0 to the first buffered range to count as
+ // "buffered" for HAVE_FUTURE_DATA / canplay; HTMLMediaElement.buffered
+ // reported to JS is unaffected.
+ // - midStreamGapTolerance: default tolerance for gaps mid-stream;
+ // gaps below this are skipped.
+ // - audioCoveredGapTolerance: widened tolerance applied when an audio
+ // track bridges a gap (typically a video-only gap with audio
+ // continuous through it).
+ static constexpr MediaTime startGapAllowance() { return { 1, 1 }; }
+ static constexpr MediaTime midStreamGapTolerance() { return { 125, 1000 }; }
+ static constexpr MediaTime audioCoveredGapTolerance() { return { 250, 1000 }; }
+
+ // Returns the gap tolerance that should apply at `time`:
+ // - startGapAllowance if `time` is in the start-of-stream window;
+ // - audioCoveredGapTolerance if some active audio track other than
+ // `excluded` has `time` inside its buffered range;
+ // - midStreamGapTolerance otherwise.
+ //
+ // When `excluded` is unset the implementation reads a lock-protected
+ // audio-buffered cache and may be called from any thread. When
+ // `excluded` is set the caller MUST be on the dispatcher (used by
+ // TrackBuffer's IsCoveredByOtherTracks callback).
+ MediaTime gapToleranceAtTime(const MediaTime&, std::optional excluded = std::nullopt) const;
+ bool isWithinStartGapAllowance(const MediaTime&) const;
MediaTime duration() const;
PlatformTimeRanges buffered() const;
@@ -139,6 +164,7 @@ class WEBCORE_EXPORT MediaSourcePrivate
bool isBuffered(const PlatformTimeRanges&) const;
PlatformTimeRanges seekable() const;
+ MediaTime nextStallTime(const MediaTime& currentTime) const;
bool hasBufferedData() const;
bool hasCurrentTime() const;
bool hasFutureTime() const;
@@ -181,13 +207,13 @@ class WEBCORE_EXPORT MediaSourcePrivate
MediaTime m_duration WTF_GUARDED_BY_LOCK(m_lock) { MediaTime::invalidTime() };
PlatformTimeRanges m_buffered WTF_GUARDED_BY_LOCK(m_lock);
+ PlatformTimeRanges m_audioBuffered WTF_GUARDED_BY_LOCK(m_lock);
std::optional m_pendingSeekTarget WTF_GUARDED_BY_LOCK(m_lock);
std::optional m_waitForTargetPromise WTF_GUARDED_BY_CAPABILITY(m_dispatcher.get());
HashMap> m_bufferedRanges;
PlatformTimeRanges m_liveSeekable WTF_GUARDED_BY_LOCK(m_lock);
std::atomic m_streaming { false };
std::atomic m_streamingAllowed { false };
- MediaTime m_timeFudgeFactor;
HashMap m_tracksTypes WTF_GUARDED_BY_CAPABILITY(m_dispatcher.get());
std::atomic m_tracksCombinedTypes;
const ThreadSafeWeakPtr m_client;
diff --git a/Source/WebCore/platform/graphics/PixelBufferConversion.cpp b/Source/WebCore/platform/graphics/PixelBufferConversion.cpp
index c9974199cf08..0ff1a6eba25e 100644
--- a/Source/WebCore/platform/graphics/PixelBufferConversion.cpp
+++ b/Source/WebCore/platform/graphics/PixelBufferConversion.cpp
@@ -113,6 +113,12 @@ static void convertImagePixelsAccelerated(const ConstPixelBufferConversionView&
auto sourceVImageBuffer = makeVImageBuffer(source, destinationSize);
auto destinationVImageBuffer = makeVImageBuffer(destination, destinationSize);
+ auto zeroFillDestination = [&] {
+ size_t rowFillBytes = static_cast(destinationSize.width()) * 4;
+ for (int y = 0; y < destinationSize.height(); ++y)
+ zeroSpan(destination.rows.subspan(static_cast(y) * destination.bytesPerRow, rowFillBytes));
+ };
+
if (source.format.colorSpace != destination.format.colorSpace) {
// FIXME: Consider using vImageConvert_AnyToAny for all conversions, not just ones that need a color space conversion,
// after judiciously performance testing them against each other.
@@ -122,11 +128,20 @@ static void convertImagePixelsAccelerated(const ConstPixelBufferConversionView&
vImage_Error converterCreateError = kvImageNoError;
auto converter = adoptCF(vImageConverter_CreateWithCGImageFormat(&sourceCGImageFormat, &destinationCGImageFormat, nullptr, kvImageNoFlags, &converterCreateError));
- if (converterCreateError != kvImageNoError)
+ if (converterCreateError != kvImageNoError) {
+ RELEASE_LOG_ERROR(Images, "%s: vImageConverter_CreateWithCGImageFormat() failed with error: %zd", __FUNCTION__, converterCreateError);
+ // The destination may be uninitialized; ensure no stale heap is exposed to callers.
+ zeroFillDestination();
return;
+ }
vImage_Error converterConvertError = vImageConvert_AnyToAny(converter.get(), &sourceVImageBuffer, &destinationVImageBuffer, nullptr, kvImageNoFlags);
- ASSERT_WITH_MESSAGE_UNUSED(converterConvertError, converterConvertError == kvImageNoError, "vImageConvert_AnyToAny failed conversion with error: %zd", converterConvertError);
+ if (converterConvertError != kvImageNoError) {
+ RELEASE_LOG_ERROR(Images, "%s: vImageConvert_AnyToAny() failed with error: %zd", __FUNCTION__, converterConvertError);
+ // The destination may be uninitialized; ensure no stale heap is exposed to callers.
+ zeroFillDestination();
+ }
+
return;
}
@@ -343,8 +358,9 @@ static void writeFloat16(Float16 f16, const std::span& spanFloat16, siz
static void convertImagePixelsFromFloat16ToFloat16(const ConstPixelBufferConversionView& source, const PixelBufferConversionView& destination, const IntSize& destinationSize)
{
- if (source.format.colorSpace != destination.format.colorSpace)
- return;
+ // FIXME: Float16-to-Float16 color-space conversion is unimplemented; fall through and copy
+ // verbatim. Do not early-return on a color-space mismatch: the destination is allocated
+ // uninitialized, so skipping the write would leak heap bytes through getPixelBuffer().
auto sourceBytes = source.rows.size_bytes();
auto sourcePixelComponents = sourceBytes / 2;
diff --git a/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp b/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp
index 6ae78ecceab4..611c72131b26 100644
--- a/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp
+++ b/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp
@@ -270,7 +270,19 @@ bool PlatformTimeRanges::containWithEpsilon(const MediaTime& time, const MediaTi
return findWithEpsilon(time, epsilon) != notFound;
}
+bool PlatformTimeRanges::containWithEpsilon(const MediaTime& time, NOESCAPE const Function& epsilonAtTime) const
+{
+ return findWithEpsilon(time, epsilonAtTime(time)) != notFound;
+}
+
bool PlatformTimeRanges::containWithEpsilon(const PlatformTimeRanges& ranges, const MediaTime& epsilon) const
+{
+ return containWithEpsilon(ranges, [&](const MediaTime&) {
+ return epsilon;
+ });
+}
+
+bool PlatformTimeRanges::containWithEpsilon(const PlatformTimeRanges& ranges, NOESCAPE const Function& epsilonAtTime) const
{
if (ranges.length() < 1)
return true;
@@ -285,7 +297,7 @@ bool PlatformTimeRanges::containWithEpsilon(const PlatformTimeRanges& ranges, co
return false;
auto hasBufferedTime = [&] (const MediaTime& time) {
- return abs(bufferedRanges.nearest(time) - time) <= epsilon;
+ return abs(bufferedRanges.nearest(time) - time) <= epsilonAtTime(time);
};
if (!hasBufferedTime(ranges.minimumBufferedTime()) || !hasBufferedTime(ranges.maximumBufferedTime()))
@@ -294,9 +306,9 @@ bool PlatformTimeRanges::containWithEpsilon(const PlatformTimeRanges& ranges, co
if (bufferedRanges.length() == 1)
return true;
- // Ensure that if we have a gap in the buffered range, it is smaller than the fudge factor;
+ // Ensure that if we have a gap in the buffered range, it is smaller than the epsilon tolerance at the gap's start;
for (unsigned i = 1; i < bufferedRanges.length(); i++) {
- if (bufferedRanges.start(i) - bufferedRanges.end(i - 1) > epsilon)
+ if (bufferedRanges.start(i) - bufferedRanges.end(i - 1) > epsilonAtTime(bufferedRanges.end(i - 1)))
return false;
}
diff --git a/Source/WebCore/platform/graphics/PlatformTimeRanges.h b/Source/WebCore/platform/graphics/PlatformTimeRanges.h
index a1fbb4d0acb7..2bb8c4528f9b 100644
--- a/Source/WebCore/platform/graphics/PlatformTimeRanges.h
+++ b/Source/WebCore/platform/graphics/PlatformTimeRanges.h
@@ -78,6 +78,12 @@ class WEBCORE_EXPORT PlatformTimeRanges final {
bool contain(const MediaTime&) const;
bool containWithEpsilon(const MediaTime&, const MediaTime& epsilon) const;
bool containWithEpsilon(const PlatformTimeRanges&, const MediaTime& epsilon) const;
+ // Variable-epsilon overloads: `epsilonAtTime(t)` is consulted at every
+ // boundary / gap location (rangeMin, rangeMax, and between adjacent
+ // sub-ranges). Used by the MSE gap-skipping policy where the
+ // tolerance varies by stream position.
+ bool containWithEpsilon(const MediaTime&, NOESCAPE const Function& epsilonAtTime) const;
+ bool containWithEpsilon(const PlatformTimeRanges&, NOESCAPE const Function& epsilonAtTime) const;
size_t find(const MediaTime&) const;
size_t findWithEpsilon(const MediaTime&, const MediaTime& epsilon) const;
@@ -132,6 +138,8 @@ class WEBCORE_EXPORT PlatformTimeRanges final {
friend bool operator==(const Range&, const Range&) = default;
};
+ std::span span() const LIFETIME_BOUND { return m_ranges.span(); }
+
friend bool operator==(const PlatformTimeRanges&, const PlatformTimeRanges&) = default;
private:
diff --git a/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp b/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
index cc5438a6b44d..9ca485e9bf19 100644
--- a/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
+++ b/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
@@ -488,7 +488,7 @@ void SourceBufferPrivate::reenqueueMediaForTime(TrackBuffer& trackBuffer, TrackI
bool isEnded = false;
if (RefPtr mediaSource = m_mediaSource.get())
isEnded = mediaSource->isEnded();
- if (trackBuffer.reenqueueMediaForTime(time, timeFudgeFactor(), isEnded))
+ if (trackBuffer.reenqueueMediaForTime(time, isEnded))
provideMediaData(trackBuffer, trackID);
}
@@ -821,7 +821,13 @@ void SourceBufferPrivate::addTrackBuffer(TrackID trackId, RefPtrtimeFudgeFactor() : PlatformTimeRanges::timeFudgeFactor());
+ UniqueRef trackBuffer = mediaSource
+ ? TrackBuffer::create(WTF::move(description),
+ [weakMediaSource = ThreadSafeWeakPtr { *mediaSource }, trackId](const MediaTime& fromTime, const MediaTime& toTime) -> bool {
+ RefPtr ms = weakMediaSource.get();
+ return ms && (toTime - fromTime) <= ms->gapToleranceAtTime(fromTime, trackId);
+ })
+ : TrackBuffer::create(WTF::move(description));
#if !RELEASE_LOG_DISABLED
// False positive see webkit.org/b/302520
SUPPRESS_UNCOUNTED_ARG trackBuffer->setLogger(protect(buffer.logger()), buffer.logIdentifier());
@@ -1767,6 +1773,34 @@ void SourceBufferPrivate::iterateTrackBuffers(NOESCAPE const Function excluded) const
+{
+ assertIsCurrent(m_dispatcher.get());
+ for (auto& [trackID, trackBuffer] : m_trackBufferMap) {
+ if (excluded && *excluded == trackID)
+ continue;
+ const auto& description = trackBuffer->description();
+ if (!description || !description->isAudio())
+ continue;
+ if (trackBuffer->buffered().contain(time))
+ return true;
+ }
+ return false;
+}
+
+PlatformTimeRanges SourceBufferPrivate::audioBufferedRanges() const
+{
+ assertIsCurrent(m_dispatcher.get());
+ PlatformTimeRanges ranges;
+ for (auto& [_, trackBuffer] : m_trackBufferMap) {
+ const auto& description = trackBuffer->description();
+ if (!description || !description->isAudio())
+ continue;
+ ranges.unionWith(trackBuffer->buffered());
+ }
+ return ranges;
+}
+
// Issue flushTrack IPCs now (still on m_dispatcher) for any track whose
// renderer holds samples about to be re-enqueued. Done at the end of an
// append (or removal) operation so the flush IPC reaches the renderer
diff --git a/Source/WebCore/platform/graphics/SourceBufferPrivate.h b/Source/WebCore/platform/graphics/SourceBufferPrivate.h
index 38d54957dc89..216950c42cc4 100644
--- a/Source/WebCore/platform/graphics/SourceBufferPrivate.h
+++ b/Source/WebCore/platform/graphics/SourceBufferPrivate.h
@@ -143,6 +143,18 @@ class SourceBufferPrivate
// Methods used by MediaSourcePrivate
bool NODELETE hasReceivedFirstInitializationSegment() const;
+ // Returns true if this SourceBuffer has an audio track whose buffered
+ // ranges include `time`. If `excluded` is set, the track with that ID is
+ // skipped (used so an audio TrackBuffer doesn't claim self-coverage when
+ // querying the unified gap policy).
+ bool isAudioBufferedAt(const MediaTime&, std::optional excluded) const;
+
+ // Union of all audio TrackBuffers' buffered ranges in this
+ // SourceBuffer. Caller must be on the dispatcher; the result is a
+ // copy that's safe to merge into MediaSourcePrivate's lock-protected
+ // audio-buffered cache.
+ PlatformTimeRanges audioBufferedRanges() const;
+
virtual size_t platformMaximumBufferSize() const { return 0; }
Ref setMaximumBufferSize(size_t);
@@ -184,7 +196,6 @@ class SourceBufferPrivate
virtual Ref appendInternal(Ref