diff --git a/JSTests/modules/module-function-declaration-executable-reuse-jettison.js b/JSTests/modules/module-function-declaration-executable-reuse-jettison.js new file mode 100644 index 000000000000..fed70cebbbd5 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse-jettison.js @@ -0,0 +1,8 @@ +//@ requireOptions("--forceCodeBlockToJettisonDueToOldAge=1", "--useEagerCodeBlockJettisonTiming=1") +import { shouldBe } from "./resources/assert.js"; +import * as A from "./module-function-declaration-executable-reuse-jettison/a.js"; + +shouldBe(A.before, "f g h s"); +shouldBe(A.after, "f 42 h2 s"); +shouldBe(A.blockResult, "block"); +shouldBe(A.fAfterBlock, "f"); diff --git a/JSTests/modules/module-function-declaration-executable-reuse-jettison/a.js b/JSTests/modules/module-function-declaration-executable-reuse-jettison/a.js new file mode 100644 index 000000000000..c05efea47ca6 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse-jettison/a.js @@ -0,0 +1,16 @@ +export function f() { return "f"; } +export function g() { return "g"; } +export function h() { return "h"; } +function s() { return "s"; } +export const before = [f(), g(), h(), s()].join(" "); +g = 42; +h = function () { return "h2"; }; +Promise.resolve().then(() => { fullGC(); }); +await 0; +export const after = [f(), g, h(), s()].join(" "); +export let blockResult; +{ + function f() { return "block"; } + blockResult = f(); +} +export const fAfterBlock = f(); diff --git a/JSTests/modules/module-function-declaration-executable-reuse.js b/JSTests/modules/module-function-declaration-executable-reuse.js new file mode 100644 index 000000000000..051885eee79c --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse.js @@ -0,0 +1,23 @@ +import { shouldBe } from "./resources/assert.js"; +import * as A from "./module-function-declaration-executable-reuse/a.js"; +import * as Same1 from "./module-function-declaration-executable-reuse/same-1.js"; +import * as Same2 from "./module-function-declaration-executable-reuse/same-2.js"; + +shouldBe(A.f(), "f"); +shouldBe(A.blockResult, "block"); +shouldBe(A.gSeenInB, "g"); +shouldBe(A.hSeenInB, "h"); +shouldBe(A.kSeenInB, "k"); +shouldBe(A.gInBody(), "replaced"); +shouldBe(A.hInBody, 42); +shouldBe(A.kInBody, Math.max); +shouldBe(A.callCaptured(), "captured"); +shouldBe(A.localResult, "local"); +shouldBe(A.gen().next().value, "gen"); +shouldBe(typeof A.asyncFn, "function"); +shouldBe(typeof A.asyncGen, "function"); + +shouldBe(Same1.fInBody, Same2.f); +shouldBe(Same2.fInBody, Same1.f); +shouldBe(Same1.f(), "f"); +shouldBe(Same2.f(), "f"); diff --git a/JSTests/modules/module-function-declaration-executable-reuse/a.js b/JSTests/modules/module-function-declaration-executable-reuse/a.js new file mode 100644 index 000000000000..942ea174defb --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse/a.js @@ -0,0 +1,29 @@ +import { gSeenInB, hSeenInB, kSeenInB } from "./b.js"; + +export function f() { return "f"; } +export function g() { return "g"; } +export function h() { return "h"; } +export function k() { return "k"; } +export function setG(value) { g = value; } +export function setH(value) { h = value; } +export function setK(value) { k = value; } +export function* gen() { yield "gen"; } +export async function asyncFn() { return "async"; } +export async function* asyncGen() { yield "asyncGen"; } + +function captured() { return "captured"; } +export function callCaptured() { return captured(); } + +function local() { return "local"; } +export const localResult = local(); + +export let blockResult; +{ + function f() { return "block"; } + blockResult = f(); +} + +export const gInBody = g; +export const hInBody = h; +export const kInBody = k; +export { gSeenInB, hSeenInB, kSeenInB }; diff --git a/JSTests/modules/module-function-declaration-executable-reuse/b.js b/JSTests/modules/module-function-declaration-executable-reuse/b.js new file mode 100644 index 000000000000..27ef24c9eb97 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse/b.js @@ -0,0 +1,8 @@ +import { g, h, k, setG, setH, setK } from "./a.js"; + +export const gSeenInB = g(); +export const hSeenInB = h(); +export const kSeenInB = k(); +setG(function () { return "replaced"; }); +setH(42); +setK(Math.max); diff --git a/JSTests/modules/module-function-declaration-executable-reuse/same-1.js b/JSTests/modules/module-function-declaration-executable-reuse/same-1.js new file mode 100644 index 000000000000..3c5106893999 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse/same-1.js @@ -0,0 +1,4 @@ +import "./same-setter.js"; +export function f() { return "f"; } +export function setF(value) { f = value; } +export const fInBody = f; diff --git a/JSTests/modules/module-function-declaration-executable-reuse/same-2.js b/JSTests/modules/module-function-declaration-executable-reuse/same-2.js new file mode 100644 index 000000000000..3c5106893999 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse/same-2.js @@ -0,0 +1,4 @@ +import "./same-setter.js"; +export function f() { return "f"; } +export function setF(value) { f = value; } +export const fInBody = f; diff --git a/JSTests/modules/module-function-declaration-executable-reuse/same-setter.js b/JSTests/modules/module-function-declaration-executable-reuse/same-setter.js new file mode 100644 index 000000000000..6ec2b611f0c2 --- /dev/null +++ b/JSTests/modules/module-function-declaration-executable-reuse/same-setter.js @@ -0,0 +1,5 @@ +import { f, setF } from "./same-1.js"; +import { f as f2, setF as setF2 } from "./same-2.js"; + +setF(f2); +setF2(f); diff --git a/JSTests/stress/arguments-elimination-inlined-load-varargs-preserves-recoveries.js b/JSTests/stress/arguments-elimination-inlined-load-varargs-preserves-recoveries.js new file mode 100644 index 000000000000..6a9e21ffb290 --- /dev/null +++ b/JSTests/stress/arguments-elimination-inlined-load-varargs-preserves-recoveries.js @@ -0,0 +1,84 @@ +//@ runDefault("--thresholdForJITAfterWarmUp=10", "--thresholdForFTLOptimizeAfterWarmUp=1000", "--useConcurrentJIT=false", "--validateFTLOSRExitLiveness=true") + +"use strict"; + +function shouldBe(actual, expected) +{ + if (actual !== expected) + throw new Error("bad value: " + actual + ", expected: " + expected); +} + +function five(values1, values2) +{ + let result = null; + for (let i = 0; i < 5; ++i) { + function arg() { "use strict"; return arguments; } + const a = arg.apply(undefined, values1); + const b = arg.apply(undefined, values2); + try { + (3881)(b); + } catch (error) { + a.toString(); + result = a; + } + } + return result; +} + +function eight(values1, values2) +{ + let result = null; + for (let i = 0; i < 5; ++i) { + function arg() { "use strict"; return arguments; } + const a = arg.apply(undefined, values1); + const b = arg.apply(undefined, values2); + try { + (3881)(b); + } catch (error) { + a.toString(); + result = a; + } + } + return result; +} + +function filled(length, value) +{ + const result = []; + for (let i = 0; i < length; ++i) + result.push(value); + return result; +} + +const fiveMarker = { marker: "five" }; +const eightMarker = { marker: "eight" }; +const seedArray = [{ marker: "seed" }, 1, 2, 3, 4, 5]; + +const firstFive = filled(5, fiveMarker); +const overwriteFive = filled(30, fiveMarker); +overwriteFive[22] = 9; + +const firstEight = filled(8, eightMarker); +const overwriteEight = filled(30, eightMarker); +overwriteEight[20] = 9; + +for (let i = 0; i < testLoopCount; ++i) { + five(firstFive, overwriteFive); + eight(firstEight, overwriteEight); +} + +const seedValues = filled(30, seedArray); +seedValues[20] = 9; +for (let i = 0; i < testLoopCount; ++i) + eight(firstEight, seedValues); + +const recoveredEight = eight(firstEight, seedValues); +shouldBe(recoveredEight.length, firstEight.length); +for (let i = 0; i < firstEight.length; ++i) + shouldBe(recoveredEight[i], eightMarker); + +const recoveredFive = five(firstFive, overwriteFive); +shouldBe(recoveredFive.length, firstFive.length); +for (let i = 0; i < firstFive.length; ++i) + shouldBe(recoveredFive[i], fiveMarker); +shouldBe(recoveredFive[5], undefined); diff --git a/JSTests/stress/arguments-elimination-load-varargs-kills-promoted-recoveries.js b/JSTests/stress/arguments-elimination-load-varargs-kills-promoted-recoveries.js new file mode 100644 index 000000000000..aa818cb6d313 --- /dev/null +++ b/JSTests/stress/arguments-elimination-load-varargs-kills-promoted-recoveries.js @@ -0,0 +1,88 @@ +//@ runDefault("--thresholdForJITAfterWarmUp=10", "--thresholdForFTLOptimizeAfterWarmUp=1000", "--useConcurrentJIT=false") + +"use strict"; + +function shouldBe(actual, expected) +{ + if (actual !== expected) + throw new Error("bad value: " + actual + ", expected: " + expected); +} +noInline(shouldBe); + +function five(values1, values2) +{ + let result = null; + for (let i = 0; i < 5; ++i) { + function arg() { "use strict"; return arguments; } + const a = arg.apply(undefined, values1); + const b = arg.apply(undefined, values2); + try { + (3881)(b); + } catch (error) { + a.toString(); + result = a; + } + } + return result; +} +noInline(five); + +function eight(values1, values2) +{ + let result = null; + for (let i = 0; i < 5; ++i) { + function arg() { "use strict"; return arguments; } + const a = arg.apply(undefined, values1); + const b = arg.apply(undefined, values2); + try { + (3881)(b); + } catch (error) { + a.toString(); + result = a; + } + } + return result; +} +noInline(eight); + +function filled(length, value) +{ + const result = []; + for (let i = 0; i < length; ++i) + result.push(value); + return result; +} +noInline(filled); + +const fiveMarker = { marker: "five" }; +const eightMarker = { marker: "eight" }; +const seedArray = [{ marker: "seed" }, 1, 2, 3, 4, 5]; + +const firstFive = filled(5, fiveMarker); +const overwriteFive = filled(30, fiveMarker); +overwriteFive[22] = 9; + +const firstEight = filled(8, eightMarker); +const overwriteEight = filled(30, eightMarker); +overwriteEight[20] = 9; + +for (let i = 0; i < testLoopCount; ++i) { + five(firstFive, overwriteFive); + eight(firstEight, overwriteEight); +} + +const seedValues = filled(30, seedArray); +seedValues[20] = 9; +for (let i = 0; i < testLoopCount; ++i) + eight(firstEight, seedValues); + +const recoveredEight = eight(firstEight, seedValues); +shouldBe(recoveredEight.length, firstEight.length); +for (let i = 0; i < firstEight.length; ++i) + shouldBe(recoveredEight[i], eightMarker); + +const recoveredFive = five(firstFive, overwriteFive); +shouldBe(recoveredFive.length, firstFive.length); +for (let i = 0; i < firstFive.length; ++i) + shouldBe(recoveredFive[i], fiveMarker); +shouldBe(recoveredFive[5], undefined); diff --git a/JSTests/stress/dfg-string-replace-regexp-unicode-empty-match-surrogate-pair.js b/JSTests/stress/dfg-string-replace-regexp-unicode-empty-match-surrogate-pair.js new file mode 100644 index 000000000000..2358412ed00a --- /dev/null +++ b/JSTests/stress/dfg-string-replace-regexp-unicode-empty-match-surrogate-pair.js @@ -0,0 +1,37 @@ +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error(`bad value: ${JSON.stringify(actual)}, expected ${JSON.stringify(expected)}`); +} + +function replaceUnicode() { + return "a\u{1F600}b".replace(/(?:)/gu, "-"); +} +noInline(replaceUnicode); + +function replaceUnicodeSets() { + return "a\u{1F600}b".replace(/(?:)/gv, "-"); +} +noInline(replaceUnicodeSets); + +function replaceAllUnicode() { + return "\u{1F600}\u{1F601}".replaceAll(/(?:)/gu, "|"); +} +noInline(replaceAllUnicode); + +function replaceLoneLead() { + return "a\uD83D".replace(/(?:)/gu, "-"); +} +noInline(replaceLoneLead); + +function replaceNonUnicode() { + return "a\u{1F600}b".replace(/(?:)/g, "-"); +} +noInline(replaceNonUnicode); + +for (var i = 0; i < testLoopCount; ++i) { + shouldBe(replaceUnicode(), "-a-\u{1F600}-b-"); + shouldBe(replaceUnicodeSets(), "-a-\u{1F600}-b-"); + shouldBe(replaceAllUnicode(), "|\u{1F600}|\u{1F601}|"); + shouldBe(replaceLoneLead(), "-a-\uD83D-"); + shouldBe(replaceNonUnicode(), "-a-\uD83D-\uDE00-b-"); +} diff --git a/JSTests/stress/for-of-mixed-element-types-value-profile.js b/JSTests/stress/for-of-mixed-element-types-value-profile.js new file mode 100644 index 000000000000..ef79286c34f1 --- /dev/null +++ b/JSTests/stress/for-of-mixed-element-types-value-profile.js @@ -0,0 +1,40 @@ +//@ skip if not $jitTests +//@ $skipModes << :lockdown +//@ requireOptions("--forceUnlinkedDFG=0") + +// The baseline JIT's fast-array op_iterator_next path must profile the iterated element into the +// getValue checkpoint's value profile. When it wrote to the computeNext slot instead, the DFG kept +// predicting the loop variable from whatever the LLInt had sampled, so it re-speculated the same +// wrong type on every recompilation until the reoptimization retry counter ran out. + +function events(i) +{ + // Only the baseline JIT ever sees the number: by iteration 20000 this function is long past the + // LLInt. + return i < 20000 ? ["a", "bb", "ccc"] : ["a", "bb", 0]; +} +noInline(events); + +function walk(i) +{ + let count = 0; + for (let event of events(i)) { + if (typeof event === "number") + count += event; + else + count += event.length; + } + return count; +} +noInline(walk); + +let total = 0; +for (let i = 0; i < 300000; ++i) + total += walk(i); + +if (total !== 960000) + throw new Error(`bad result: ${total}`); + +const compiles = numberOfDFGCompiles(walk); +if (compiles > 4) + throw new Error(`walk was DFG-compiled ${compiles} times; the loop variable's value profile is not being updated`); diff --git a/JSTests/stress/ftl-osr-exit-materialize-phantom-array-with-live-butterfly.js b/JSTests/stress/ftl-osr-exit-materialize-phantom-array-with-live-butterfly.js index ed77f790fcee..aceb48a33f53 100644 --- a/JSTests/stress/ftl-osr-exit-materialize-phantom-array-with-live-butterfly.js +++ b/JSTests/stress/ftl-osr-exit-materialize-phantom-array-with-live-butterfly.js @@ -1,3 +1,4 @@ +//@ slow! //@ runDefault("--forceEagerCompilation=1") let total = 0; diff --git a/JSTests/stress/regexp-dot-star-enclosure-dot-all-last-index.js b/JSTests/stress/regexp-dot-star-enclosure-dot-all-last-index.js new file mode 100644 index 000000000000..109882bf626f --- /dev/null +++ b/JSTests/stress/regexp-dot-star-enclosure-dot-all-last-index.js @@ -0,0 +1,94 @@ +function shouldBe(actual, expected) { + if (actual !== expected) + throw new Error("bad value: " + actual + " expected: " + expected); +} + +// Checks exec(), the lastIndex it leaves behind, and test(), which share the compiled path. +function check(re, lastIndex, string, expectedIndex, expectedMatch) { + re.lastIndex = lastIndex; + const result = re.exec(string); + if (expectedMatch === null) { + shouldBe(result, null); + shouldBe(re.lastIndex, 0); + } else { + shouldBe(result[0], expectedMatch); + shouldBe(result.index, expectedIndex); + shouldBe(re.lastIndex, expectedIndex + expectedMatch.length); + } + + re.lastIndex = lastIndex; + shouldBe(re.test(string), expectedMatch !== null); +} + +const dotAll = /.*X.*/gs; +const dotAllEOL = /.*X.*$/gs; +const dotAllMultiline = /.*X.*/gms; +// `s` is a no-op by construction here, since [\s\S] already matches every code point, so this must +// agree with the plain `g` spelling below. +const explicitAnyDotAll = new RegExp("[\\s\\S]*X[\\s\\S]*", "gs"); +const plain = /.*X.*/g; + +const bolDotAll = /^.*X.*/gs; +const bolEOLDotAll = /^.*X.*$/gs; +const bolDotAllMultiline = /^.*X.*/gms; +const bolEOLDotAllMultiline = /^.*X.*$/gms; +const bolPlain = /^.*X.*/g; +const bolPlainMultiline = /^.*X.*/gm; + +function step() { + // 1. A global match must begin at or after lastIndex. + check(dotAll, 0, "aaXb", 0, "aaXb"); + check(dotAll, 1, "aaXb", 1, "aXb"); + check(dotAll, 2, "aaXb", 2, "Xb"); + check(dotAll, 3, "aaXb", 0, null); + check(dotAll, 4, "aaXb", 0, null); + + check(dotAllEOL, 1, "aaXb", 1, "aXb"); + check(dotAll, 1, "aaXbXc", 1, "aXbXc"); + + // The enclosure still reaches across line terminators; it just cannot reach past lastIndex. + check(dotAll, 1, "aa\nXb", 1, "a\nXb"); + check(dotAllMultiline, 1, "aa\nXb", 1, "a\nXb"); + + check(explicitAnyDotAll, 1, "aaXb", 1, "aXb"); + check(plain, 1, "aaXb", 1, "aXb"); + + // matchAll() starts from lastIndex too, and its first yield was wrong for the same reason. + dotAll.lastIndex = 0; + const all = [...("aaXb".matchAll(dotAll))]; + shouldBe(all.length, 1); + shouldBe(all[0].index, 0); + shouldBe(all[0][0], "aaXb"); + + // 2. `^` still has to hold where the match is reported to begin. + check(bolDotAll, 0, "aaXb", 0, "aaXb"); + check(bolDotAll, 1, "aaXb", 0, null); + check(bolDotAll, 2, "aaXb", 0, null); + check(bolEOLDotAll, 0, "aaXb", 0, "aaXb"); + check(bolEOLDotAll, 1, "aaXb", 0, null); + + // Non-zero lastIndex is fine when `^` genuinely holds: under `m` it holds after a newline. + check(bolDotAllMultiline, 0, "aa\nXb", 0, "aa\nXb"); + check(bolDotAllMultiline, 1, "aa\nXb", 3, "Xb"); + check(bolDotAllMultiline, 3, "aa\nXb", 3, "Xb"); + check(bolDotAllMultiline, 1, "aaXb", 0, null); + check(bolEOLDotAllMultiline, 1, "aa\nXb", 3, "Xb"); + + // Under `m` the match can even have to begin at a line start *after* the X the enclosure would + // have matched: the leftmost X is at 1, but `^` does not hold there, so the match is "cXd" at 4. + // Widening backwards cannot reach that, which is why these patterns skip the enclosure. + check(bolDotAllMultiline, 1, "aXb\ncXd", 4, "cXd"); + check(bolDotAllMultiline, 2, "aXb\ncXd", 4, "cXd"); + check(bolDotAllMultiline, 4, "aXb\ncXd", 4, "cXd"); + check(bolDotAllMultiline, 5, "aXb\ncXd", 0, null); + check(bolEOLDotAllMultiline, 1, "aXb\ncXd", 4, "cXd"); + + // Non-dotAll spellings keep using the enclosure and must be unaffected. + check(bolPlain, 0, "aaXb", 0, "aaXb"); + check(bolPlain, 1, "aaXb", 0, null); + check(bolPlainMultiline, 0, "aa\nXb", 3, "Xb"); + check(bolPlainMultiline, 1, "aa\nXb", 3, "Xb"); +} + +for (var i = 0; i < testLoopCount; ++i) + step(); diff --git a/JSTests/wasm.yaml b/JSTests/wasm.yaml index ae481b41bdbb..80d6f5fa6df7 100644 --- a/JSTests/wasm.yaml +++ b/JSTests/wasm.yaml @@ -53,6 +53,8 @@ cmd: runV8WebAssemblySuite(:no_module, "mjsunit.js") unless parseRunCommands - path: wasm/branch-hints cmd: runWebAssemblySuite unless parseRunCommands +- path: wasm/extended-const + cmd: runWebAssemblySuite unless parseRunCommands - path: wasm/threads-spec-tests cmd: runWebAssemblyThreadsSpecTest :normal diff --git a/JSTests/wasm/extended-const/extended-const.js b/JSTests/wasm/extended-const/extended-const.js index b273086a583d..76fbb68b516d 100644 --- a/JSTests/wasm/extended-const/extended-const.js +++ b/JSTests/wasm/extended-const/extended-const.js @@ -309,8 +309,7 @@ async function testExtendedConstElement() { assert.eq(m.exports.t.get(43), null); } - // FIXME: this requires changing how element segment initialization vectors are parsed. - // Test element segment kind 6.with element init expression. + // Test element segment kind 6 with element init expression. /* * (module * (global (import "m" "gi1") externref) @@ -318,17 +317,17 @@ async function testExtendedConstElement() { * (elem (table 0) (offset (i32.add (i32.const 1) (i32.const 42))) externref (global.get 0)) * ) */ - //{ - // let obj = "hello"; - // let m = new WebAssembly.Instance( - // module("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x8a\x80\x80\x80\x00\x01\x01\x6d\x03\x67\x69\x31\x03\x6f\x00\x04\x84\x80\x80\x80\x00\x01\x6f\x00\x40\x07\x85\x80\x80\x80\x00\x01\x01\x74\x01\x00\x09\x8e\x80\x80\x80\x00\x01\x06\x00\x41\x01\x41\x2a\x6a\x0b\x6f\x01\x23\x00\x0b"), - // { m: { gi1: obj } } - // ); - // assert.eq(m.exports.t.get(0), null); - // assert.eq(m.exports.t.get(42), null); - // assert.eq(m.exports.t.get(43), obj); - // assert.eq(m.exports.t.get(44), null); - //} + { + let obj = "hello"; + let m = new WebAssembly.Instance( + module("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x8a\x80\x80\x80\x00\x01\x01\x6d\x03\x67\x69\x31\x03\x6f\x00\x04\x84\x80\x80\x80\x00\x01\x6f\x00\x40\x07\x85\x80\x80\x80\x00\x01\x01\x74\x01\x00\x09\x8e\x80\x80\x80\x00\x01\x06\x00\x41\x01\x41\x2a\x6a\x0b\x6f\x01\x23\x00\x0b"), + { m: { gi1: obj } } + ); + assert.eq(m.exports.t.get(0), null); + assert.eq(m.exports.t.get(42), null); + assert.eq(m.exports.t.get(43), obj); + assert.eq(m.exports.t.get(44), null); + } } async function testExtendedConstData() { diff --git a/JSTests/wasm/js-api/js-module-mutable-global-export.js b/JSTests/wasm/js-api/js-module-mutable-global-export.js new file mode 100644 index 000000000000..f7930af3a1f6 --- /dev/null +++ b/JSTests/wasm/js-api/js-module-mutable-global-export.js @@ -0,0 +1 @@ +export const g = new WebAssembly.Global({ value: "i32", mutable: true }, 1); diff --git a/JSTests/wasm/js-api/js-module-mutable-global-namespace.js b/JSTests/wasm/js-api/js-module-mutable-global-namespace.js new file mode 100644 index 000000000000..c1c3fb61368f --- /dev/null +++ b/JSTests/wasm/js-api/js-module-mutable-global-namespace.js @@ -0,0 +1,8 @@ +import * as ns from "./js-module-mutable-global-export.js" +import * as assert from "../assert.js"; + +assert.instanceof(ns.g, WebAssembly.Global); +assert.eq(ns.g.value, 1); +ns.g.value = 7; +assert.eq(ns.g.value, 7); +assert.instanceof(ns.g, WebAssembly.Global); diff --git a/JSTests/wasm/js-api/js-reexport-wasm-mut-global-namespace.js b/JSTests/wasm/js-api/js-reexport-wasm-mut-global-namespace.js new file mode 100644 index 000000000000..536b75e55b23 --- /dev/null +++ b/JSTests/wasm/js-api/js-reexport-wasm-mut-global-namespace.js @@ -0,0 +1,7 @@ +import * as ns from "./js-reexport-wasm-mut-global.js" +import * as assert from "../assert.js"; + +assert.eq(ns.g, 100); +ns.set(3); +assert.eq(ns.get(), 3); +assert.eq(ns.g, 3); diff --git a/JSTests/wasm/js-api/js-reexport-wasm-mut-global.js b/JSTests/wasm/js-api/js-reexport-wasm-mut-global.js new file mode 100644 index 000000000000..359daa4f59d2 --- /dev/null +++ b/JSTests/wasm/js-api/js-reexport-wasm-mut-global.js @@ -0,0 +1 @@ +export { g, get, set } from "../modules/mut-global.wasm"; diff --git a/JSTests/wasm/js-api/js-wasm-imported-mut-global-namespace.js b/JSTests/wasm/js-api/js-wasm-imported-mut-global-namespace.js new file mode 100644 index 000000000000..4ef6065f266f --- /dev/null +++ b/JSTests/wasm/js-api/js-wasm-imported-mut-global-namespace.js @@ -0,0 +1,11 @@ +import * as ns from "./reexport-js-mut-global.wasm" +import { g } from "./js-module-mutable-global-export.js" +import * as assert from "../assert.js"; + +assert.eq(ns.g, 1); +assert.instanceof(g, WebAssembly.Global); +assert.eq(g.value, 1); + +g.value = 9; +assert.eq(ns.g, 9); +assert.eq(g.value, 9); diff --git a/JSTests/wasm/js-api/reexport-js-mut-global.wasm b/JSTests/wasm/js-api/reexport-js-mut-global.wasm new file mode 100644 index 000000000000..cbfac2fd3b1a Binary files /dev/null and b/JSTests/wasm/js-api/reexport-js-mut-global.wasm differ diff --git a/JSTests/wasm/js-api/reexport-js-mut-global.wat b/JSTests/wasm/js-api/reexport-js-mut-global.wat new file mode 100644 index 000000000000..0e8b69023c51 --- /dev/null +++ b/JSTests/wasm/js-api/reexport-js-mut-global.wat @@ -0,0 +1,3 @@ +(module + (import "./js-module-mutable-global-export.js" "g" (global $g (mut i32))) + (export "g" (global $g))) diff --git a/JSTests/wasm/js-api/test_basic_api.js b/JSTests/wasm/js-api/test_basic_api.js index 1231915b9554..fa4f19788da6 100644 --- a/JSTests/wasm/js-api/test_basic_api.js +++ b/JSTests/wasm/js-api/test_basic_api.js @@ -66,8 +66,7 @@ for (const c in constructorProperties) { for (const invalid of invalidConstructorInputs) assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`); for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()]) - // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768 - assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`); + assert.throws(() => new WebAssembly[c](buffer), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`); assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module); break; case "Instance": diff --git a/JSTests/wasm/modules/js-wasm-mutable-global-namespace.js b/JSTests/wasm/modules/js-wasm-mutable-global-namespace.js new file mode 100644 index 000000000000..8b2ce01950c6 --- /dev/null +++ b/JSTests/wasm/modules/js-wasm-mutable-global-namespace.js @@ -0,0 +1,13 @@ +import * as ns from "./mut-global.wasm" +import * as assert from '../assert.js'; + +assert.eq(ns.g, 100); +assert.eq(ns.get(), 100); + +ns.set(555); +assert.eq(ns.get(), 555); +assert.eq(ns.g, 555); + +assert.throws(() => { + ns.g = 1; +}, TypeError, `Attempted to assign to readonly property.`); diff --git a/JSTests/wasm/modules/js-wasm-reserved-names.js b/JSTests/wasm/modules/js-wasm-reserved-names.js new file mode 100644 index 000000000000..283c865026c4 --- /dev/null +++ b/JSTests/wasm/modules/js-wasm-reserved-names.js @@ -0,0 +1,21 @@ +import * as assert from '../assert.js'; + +function assertLinkError(promise) { + return promise.then($vm.abort, function (error) { + assert.eq(error instanceof WebAssembly.LinkError, true); + }); +} + +assertLinkError(import("./reserved-import-name.wasm")) + .then(() => assertLinkError(import("./reserved-import-name-wasm-js.wasm"))) + .then(() => assertLinkError(import("./reserved-export-name.wasm"))) + .then(() => assertLinkError(import("./reserved-export-name-wasm-js.wasm"))) + .then(() => assertLinkError(import("./reserved-import-module.wasm"))) + .then(() => import("./wasm-colon-module.wasm").then($vm.abort, function (error) { + assert.eq(error instanceof WebAssembly.LinkError && String(error).includes("is reserved"), false); + })) + .then(function () { }, $vm.abort); + +const { "wasm:invalid": fn } = new WebAssembly.Instance(new WebAssembly.Module(read("./reserved-export-name.wasm", "binary"))).exports; +assert.isFunction(fn); +assert.eq(fn(), 42); diff --git a/JSTests/wasm/modules/mut-global.wasm b/JSTests/wasm/modules/mut-global.wasm new file mode 100644 index 000000000000..09baba67d34d Binary files /dev/null and b/JSTests/wasm/modules/mut-global.wasm differ diff --git a/JSTests/wasm/modules/mut-global.wat b/JSTests/wasm/modules/mut-global.wat new file mode 100644 index 000000000000..b7e8b6d0f624 --- /dev/null +++ b/JSTests/wasm/modules/mut-global.wat @@ -0,0 +1,7 @@ +(module + (global $g (mut i32) (i32.const 100)) + (func (export "set") (param i32) + (global.set $g (local.get 0))) + (func (export "get") (result i32) + (global.get $g)) + (export "g" (global $g))) diff --git a/JSTests/wasm/modules/reserved-export-name-wasm-js.wasm b/JSTests/wasm/modules/reserved-export-name-wasm-js.wasm new file mode 100644 index 000000000000..363562c7f747 Binary files /dev/null and b/JSTests/wasm/modules/reserved-export-name-wasm-js.wasm differ diff --git a/JSTests/wasm/modules/reserved-export-name-wasm-js.wat b/JSTests/wasm/modules/reserved-export-name-wasm-js.wat new file mode 100644 index 000000000000..d79575339e22 --- /dev/null +++ b/JSTests/wasm/modules/reserved-export-name-wasm-js.wat @@ -0,0 +1,3 @@ +(module + (func (export "wasm-js:invalid") (result i32) + i32.const 42)) diff --git a/JSTests/wasm/modules/reserved-export-name.wasm b/JSTests/wasm/modules/reserved-export-name.wasm new file mode 100644 index 000000000000..cd8be87943b5 Binary files /dev/null and b/JSTests/wasm/modules/reserved-export-name.wasm differ diff --git a/JSTests/wasm/modules/reserved-export-name.wat b/JSTests/wasm/modules/reserved-export-name.wat new file mode 100644 index 000000000000..a2b6ddda366b --- /dev/null +++ b/JSTests/wasm/modules/reserved-export-name.wat @@ -0,0 +1,3 @@ +(module + (func (export "wasm:invalid") (result i32) + i32.const 42)) diff --git a/JSTests/wasm/modules/reserved-import-module.wasm b/JSTests/wasm/modules/reserved-import-module.wasm new file mode 100644 index 000000000000..56d4f3f021ea Binary files /dev/null and b/JSTests/wasm/modules/reserved-import-module.wasm differ diff --git a/JSTests/wasm/modules/reserved-import-module.wat b/JSTests/wasm/modules/reserved-import-module.wat new file mode 100644 index 000000000000..7e0820a7f348 --- /dev/null +++ b/JSTests/wasm/modules/reserved-import-module.wat @@ -0,0 +1,4 @@ +(module + (import "wasm-js:invalid" "test" (func $invalid (result i32))) + (func (export "test") (result i32) + call $invalid)) diff --git a/JSTests/wasm/modules/reserved-import-name-wasm-js.wasm b/JSTests/wasm/modules/reserved-import-name-wasm-js.wasm new file mode 100644 index 000000000000..9297b2833f5a Binary files /dev/null and b/JSTests/wasm/modules/reserved-import-name-wasm-js.wasm differ diff --git a/JSTests/wasm/modules/reserved-import-name-wasm-js.wat b/JSTests/wasm/modules/reserved-import-name-wasm-js.wat new file mode 100644 index 000000000000..3fe4fe4247da --- /dev/null +++ b/JSTests/wasm/modules/reserved-import-name-wasm-js.wat @@ -0,0 +1,4 @@ +(module + (import "test" "wasm-js:invalid" (func $invalid (result i32))) + (func (export "test") (result i32) + call $invalid)) diff --git a/JSTests/wasm/modules/reserved-import-name.wasm b/JSTests/wasm/modules/reserved-import-name.wasm new file mode 100644 index 000000000000..79020e8d6144 Binary files /dev/null and b/JSTests/wasm/modules/reserved-import-name.wasm differ diff --git a/JSTests/wasm/modules/reserved-import-name.wat b/JSTests/wasm/modules/reserved-import-name.wat new file mode 100644 index 000000000000..53a6d4d478f1 --- /dev/null +++ b/JSTests/wasm/modules/reserved-import-name.wat @@ -0,0 +1,4 @@ +(module + (import "test" "wasm:invalid" (func $invalid (result i32))) + (func (export "test") (result i32) + call $invalid)) diff --git a/JSTests/wasm/modules/wasm-colon-module.wasm b/JSTests/wasm/modules/wasm-colon-module.wasm new file mode 100644 index 000000000000..37b63c127793 Binary files /dev/null and b/JSTests/wasm/modules/wasm-colon-module.wasm differ diff --git a/JSTests/wasm/modules/wasm-colon-module.wat b/JSTests/wasm/modules/wasm-colon-module.wat new file mode 100644 index 000000000000..e3d346261e4a --- /dev/null +++ b/JSTests/wasm/modules/wasm-colon-module.wat @@ -0,0 +1,2 @@ +(module + (import "wasm:not-a-builtin" "x" (func))) diff --git a/JSTests/wasm/stress/block-param-type-widening.js b/JSTests/wasm/stress/block-param-type-widening.js new file mode 100644 index 000000000000..a7925c95b52f --- /dev/null +++ b/JSTests/wasm/stress/block-param-type-widening.js @@ -0,0 +1,72 @@ +import * as assert from "../assert.js"; + +// When a block/if/try/try_table declares a parameter type that is a *supertype* +// of the value actually on the stack, the block body must be validated against +// the DECLARED type, not the narrower concrete type that flowed in +// Each case below is built twice with an identical body: +// - declared type = anyref (wide): `struct.get 0 0` is invalid on anyref, so +// the module must be REJECTED. Before widening, the body saw the concrete +// `(ref null 0)` and this was (incorrectly) accepted. +// - declared type = (ref null 0) (concrete): `struct.get 0 0` is valid, so the +// module must VALIDATE. This control confirms the scaffolding is otherwise +// well-formed, so the rejection above is due to widening alone. + +function uleb128(n) { const r = []; do { let b = n & 0x7f; n >>>= 7; if (n) b |= 0x80; r.push(b); } while (n); return r; } +function encodeString(s) { const b = []; for (let i = 0; i < s.length; i++) b.push(s.charCodeAt(i)); return [...uleb128(b.length), ...b]; } +function section(id, content) { return [id, ...uleb128(content.length), ...content]; } + +// Module layout: +// type 0: struct { i64 mut } +// type 1: (the signature of the block under test) +// type 2: func () -> i64 (the exported function "test") +function buildModule(blockSig, body0) { + const typeSection = section(1, [ + 0x03, + 0x5F, 0x01, 0x7E, 0x01, // type 0: struct { i64 mut } + ...blockSig, // type 1 + 0x60, 0x00, 0x01, 0x7E, // type 2: () -> i64 + ]); + const funcSection = section(3, [0x01, 0x02]); // func 0 : type 2 + const exportSection = section(7, [0x01, ...encodeString("test"), 0x00, 0x00]); // export "test" func 0 + const codeSection = section(10, [0x01, ...uleb128(body0.length), ...body0]); + return new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ...typeSection, ...funcSection, ...exportSection, ...codeSection]); +} + +const sigParam = (t) => [0x60, 0x01, ...t, 0x01, 0x7E]; // (t) -> (i64) +const ANYREF = [0x6E]; +const REF_NULL_0 = [0x63, 0x00]; // (ref null 0) + +const GET = [0xFB, 0x02, 0x00, 0x00]; // struct.get 0 0 +const REF_NULL_TYPE0 = [0xD0, 0x00]; // ref.null 0 -> (ref null 0) + +// name -> { sig: (refTypeBytes) -> typeEntry, body } +const cases = { + // (block (param T) (result i64) (struct.get 0 0)) + "block param": { + sig: sigParam, + body: [0x00, ...REF_NULL_TYPE0, 0x02, 0x01, ...GET, 0x0B, 0x0B], + }, + // (if (param T) (result i64) (then struct.get 0 0) (else drop i64.const 0)) + "if param": { + sig: sigParam, + body: [0x00, ...REF_NULL_TYPE0, 0x41, 0x01, 0x04, 0x01, ...GET, 0x05, 0x1A, 0x42, 0x00, 0x0B, 0x0B], + }, + // (try (param T) (result i64) (do struct.get 0 0) (catch_all i64.const 0)) + "try param": { + sig: sigParam, + body: [0x00, ...REF_NULL_TYPE0, 0x06, 0x01, ...GET, 0x19, 0x42, 0x00, 0x0B, 0x0B], + }, + // (try_table (param T) (result i64) (struct.get 0 0)) -- 0 catch clauses + "try_table param": { + sig: sigParam, + body: [0x00, ...REF_NULL_TYPE0, 0x1F, 0x01, 0x00, ...GET, 0x0B, 0x0B], + }, +}; + +for (const [name, { sig, body }] of Object.entries(cases)) { + assert.falsy(WebAssembly.validate(buildModule(sig(ANYREF), body)), + `${name}: struct.get on a widened anyref must be rejected (declared type not the concrete incoming type)`); + assert.truthy(WebAssembly.validate(buildModule(sig(REF_NULL_0), body)), + `${name}: struct.get on the concrete (ref null 0) must validate`); +} diff --git a/JSTests/wasm/stress/delegate-widens-result-type-to-signature.js b/JSTests/wasm/stress/delegate-widens-result-type-to-signature.js new file mode 100644 index 000000000000..20b86f82b44a --- /dev/null +++ b/JSTests/wasm/stress/delegate-widens-result-type-to-signature.js @@ -0,0 +1,74 @@ +import * as assert from "../assert.js"; + +function uleb128(n) { const r = []; do { let b = n & 0x7f; n >>>= 7; if (n) b |= 0x80; r.push(b); } while (n); return r; } +function encodeString(s) { const b = []; for (let i = 0; i < s.length; i++) b.push(s.charCodeAt(i)); return [...uleb128(b.length), ...b]; } +function section(id, content) { return [id, ...uleb128(content.length), ...content]; } + +function buildModule() { + const typeSection = section(1, [ + 3, + 0x5F, 0x01, 0x7E, 0x01, // type 0: struct { i64 mut } + 0x60, 0x03, 0x7F, 0x6F, 0x64, 0x00, 0x01, 0x7E, // type 1: func (i32, externref, (ref 0)) -> i64 + 0x60, 0x00, 0x01, 0x64, 0x00, // type 2: func () -> (ref 0) + ]); + const funcSection = section(3, [0x02, 0x01, 0x02]); + const exportSection = section(7, [0x02, + ...encodeString("test"), 0x00, 0x00, + ...encodeString("make"), 0x00, 0x01]); + + // (func $test (param $cond i32) (param $ext externref) (param $s (ref 0)) (result i64) + // try (result i64) ;; outer: delegate target + // try (result anyref) ;; inner + // local.get $ext + // any.convert_extern ;; -> anyref (NaN-boxed JS number) + // local.get $cond + // br_if 0 ;; carry the anyref to the inner continuation + // drop + // local.get $s ;; fallthrough: (ref 0), a subtype of anyref + // delegate 0 ;; terminates inner try; result MUST widen to anyref + // ref.cast (ref 0) ;; must NOT elide IsCell / IsWasmGCObject checks + // struct.get 0 0 + // catch_all + // i64.const 0 + // end) + const body0 = [ + 0x00, + 0x06, 0x7E, // try (result i64) + 0x06, 0x6E, // try (result anyref) + 0x20, 0x01, // local.get 1 + 0xFB, 0x1A, // any.convert_extern + 0x20, 0x00, // local.get 0 + 0x0D, 0x00, // br_if 0 + 0x1A, // drop + 0x20, 0x02, // local.get 2 + 0x18, 0x00, // delegate 0 + 0xFB, 0x16, 0x00, // ref.cast (ref 0) + 0xFB, 0x02, 0x00, 0x00, // struct.get 0 0 + 0x19, // catch_all + 0x42, 0x00, // i64.const 0 + 0x0B, // end (outer try) + 0x0B, // end (func) + ]; + // (func $make (result (ref 0)) i64.const 0x1234 struct.new 0) + const body1 = [0x00, 0x42, 0xB4, 0x24, 0xFB, 0x00, 0x00, 0x0B]; + const codeSection = section(10, [0x02, + ...uleb128(body0.length), ...body0, + ...uleb128(body1.length), ...body1]); + return new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ...typeSection, ...funcSection, ...exportSection, ...codeSection]); +} + +const bytes = buildModule(); +assert.truthy(WebAssembly.validate(bytes)); +const instance = new WebAssembly.Instance(new WebAssembly.Module(bytes)); +const struct = instance.exports.make(); + +for (let i = 0; i < wasmTestLoopCount; ++i) { + // cond == 0: br_if not taken; the try body's (ref 0) fallthrough survives the + // delegate. Widened to anyref, ref.cast succeeds and struct.get reads the field. + assert.eq(instance.exports.test(0, null, struct), 0x1234n); + // cond == 1: br_if delivers an anyref-wrapped JS number to the inner continuation. + // The post-delegate value is statically anyref, so ref.cast must perform the full + // runtime check and trap rather than dereference the non-cell value. + assert.throws(() => instance.exports.test(1, 1.5, struct), WebAssembly.RuntimeError, "ref.cast failed to cast reference to target heap type"); +} diff --git a/JSTests/wasm/stress/js-to-wasm-i31ref.js b/JSTests/wasm/stress/js-to-wasm-i31ref.js new file mode 100644 index 000000000000..c195d8040c91 --- /dev/null +++ b/JSTests/wasm/stress/js-to-wasm-i31ref.js @@ -0,0 +1,36 @@ +import { instantiate } from "../gc/wast-wrapper.js"; +import * as assert from "../assert.js"; + +let wat = ` +(module + (func (export "get") (param (ref i31)) (result i32) + (i31.get_s (local.get 0))) + (func (export "getNullable") (param i31ref) (result i32) + (if (result i32) + (ref.is_null (local.get 0)) + (then (i32.const -1)) + (else (i31.get_s (local.get 0))))) +) +`; + +async function test() { + const instance = instantiate(wat); + const { get, getNullable } = instance.exports; + + for (let i = 0; i < wasmTestLoopCount; i++) { + assert.eq(get(0), 0); + assert.eq(get(2), 2); + assert.eq(get(2 ** 30 - 1), 2 ** 30 - 1); + assert.eq(get(-(2 ** 30)), -(2 ** 30)); + assert.eq(getNullable(null), -1); + assert.eq(getNullable(7), 7); + } + + assert.throws(() => get(2.3), TypeError, "Argument value did not match the reference type"); + assert.throws(() => get(2n), TypeError, "Argument value did not match the reference type"); + assert.throws(() => get(2 ** 30), TypeError, "Argument value did not match the reference type"); + assert.throws(() => get(-(2 ** 30) - 1), TypeError, "Argument value did not match the reference type"); + assert.throws(() => get(null), TypeError, "Argument value did not match the reference type"); +} + +await assert.asyncTest(test()); diff --git a/JSTests/wasm/stress/loop-param-type-widening.js b/JSTests/wasm/stress/loop-param-type-widening.js new file mode 100644 index 000000000000..0fcedc39743e --- /dev/null +++ b/JSTests/wasm/stress/loop-param-type-widening.js @@ -0,0 +1,138 @@ +function uleb128(n) { + const r = []; + do { + let b = n & 0x7f; + n >>>= 7; + if (n) b |= 0x80; + r.push(b); + } while (n); + return r; +} +function encodeString(s) { + const b = []; + for (let i = 0; i < s.length; i++) b.push(s.charCodeAt(i)); + return [...uleb128(b.length), ...b]; +} +function section(id, content) { return [id, ...uleb128(content.length), ...content]; } + +// --- Part 1 --------------------------------------------------------------- +// A loop declaring `(param anyref)` entered with a `(ref $0)` on the stack must +// typecheck its body against `anyref`, so `struct.get 0 0` at the top of the body +// is a validation error. Previously the body was typechecked against the narrower +// `(ref $0)` and the module was (unsoundly) accepted. +{ + // Type 0: struct { i64 mut } + // Type 1: func (anyref) -> (i64) — loop block signature + // Type 2: func (i32, externref, ref 0) -> (i64) + // Type 3: func () -> (ref 0) + const typeSection = section(1, [ + 0x04, + 0x5F, 0x01, 0x7E, 0x01, + 0x60, 0x01, 0x6E, 0x01, 0x7E, + 0x60, 0x03, 0x7F, 0x6F, 0x64, 0x00, 0x01, 0x7E, + 0x60, 0x00, 0x01, 0x64, 0x00, + ]); + const funcSection = section(3, [0x02, 0x02, 0x03]); + const exportSection = section(7, [ + 0x02, + ...encodeString("f"), 0x00, 0x00, + ...encodeString("make"), 0x00, 0x01, + ]); + const body0 = [ + 0x01, 0x01, 0x7E, // 1 local: i64 + 0x20, 0x02, // local.get 2 (ref $0) + 0x03, 0x01, // loop (type 1) — param anyref + 0xFB, 0x02, 0x00, 0x00, // struct.get 0 0 <-- must fail: anyref !<: (ref null $0) + 0x21, 0x03, // local.set 3 + 0x20, 0x01, // local.get 1 (externref) + 0xFB, 0x1A, // any.convert_extern + 0x20, 0x00, // local.get 0 + 0x0D, 0x00, // br_if 0 + 0x1A, // drop + 0x20, 0x03, // local.get 3 + 0x0B, // end loop + 0x0B, // end func + ]; + const body1 = [0x00, 0x42, 0x00, 0xFB, 0x00, 0x00, 0x0B]; // i64.const 0; struct.new 0 + const codeSection = section(10, [ + 0x02, + ...uleb128(body0.length), ...body0, + ...uleb128(body1.length), ...body1, + ]); + const bin = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ...typeSection, ...funcSection, ...exportSection, ...codeSection, + ]); + + if (WebAssembly.validate(bin)) + throw new Error("Part 1: module with struct.get on anyref loop param must not validate"); +} + +// --- Part 2 --------------------------------------------------------------- +// A loop declaring `(param (ref null $0))` entered with a non-null `(ref $0)` is +// valid, but the body must be compiled against the nullable type: struct.get must +// emit its null check so a null delivered on the back-edge traps cleanly. +{ + // Type 0: struct { i64 mut } + // Type 1: func (ref null 0) -> (i64) — loop block signature + // Type 2: func (i32, ref 0) -> (i64) + // Type 3: func () -> (ref 0) + const typeSection = section(1, [ + 0x04, + 0x5F, 0x01, 0x7E, 0x01, + 0x60, 0x01, 0x63, 0x00, 0x01, 0x7E, + 0x60, 0x02, 0x7F, 0x64, 0x00, 0x01, 0x7E, + 0x60, 0x00, 0x01, 0x64, 0x00, + ]); + const funcSection = section(3, [0x02, 0x02, 0x03]); + const exportSection = section(7, [ + 0x02, + ...encodeString("f"), 0x00, 0x00, + ...encodeString("make"), 0x00, 0x01, + ]); + const body0 = [ + 0x01, 0x01, 0x7E, // 1 local: i64 + 0x20, 0x01, // local.get 1 (ref $0, non-null) + 0x03, 0x01, // loop (type 1) — param (ref null $0) + 0xFB, 0x02, 0x00, 0x00, // struct.get 0 0 <-- must keep null check + 0x21, 0x02, // local.set 2 + 0xD0, 0x71, // ref.null none + 0x20, 0x00, // local.get 0 + 0x0D, 0x00, // br_if 0 <-- back-edge with null + 0x1A, // drop + 0x20, 0x02, // local.get 2 + 0x0B, // end loop + 0x0B, // end func + ]; + const body1 = [0x00, 0x42, 0x2A, 0xFB, 0x00, 0x00, 0x0B]; // i64.const 42; struct.new 0 + const codeSection = section(10, [ + 0x02, + ...uleb128(body0.length), ...body0, + ...uleb128(body1.length), ...body1, + ]); + const bin = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ...typeSection, ...funcSection, ...exportSection, ...codeSection, + ]); + + if (!WebAssembly.validate(bin)) + throw new Error("Part 2: module must validate"); + const inst = new WebAssembly.Instance(new WebAssembly.Module(bin)); + const s = inst.exports.make(); + + for (let i = 0; i < wasmTestLoopCount; i++) { + if (inst.exports.f(0, s) !== 42n) + throw new Error("Part 2: expected 42"); + } + + let trapped = false; + try { + inst.exports.f(1, s); + } catch (e) { + if (!(e instanceof WebAssembly.RuntimeError)) + throw new Error("Part 2: expected WebAssembly.RuntimeError, got " + e); + trapped = true; + } + if (!trapped) + throw new Error("Part 2: expected null-dereference trap on back-edge"); +} diff --git a/JSTests/wasm/stress/ref-func-wrapper-identity.js b/JSTests/wasm/stress/ref-func-wrapper-identity.js new file mode 100644 index 000000000000..59a1eae1bfa7 --- /dev/null +++ b/JSTests/wasm/stress/ref-func-wrapper-identity.js @@ -0,0 +1,50 @@ +import { instantiate } from "../wabt-wrapper.js" +import * as assert from "../assert.js" + +let producerWat = ` +(module + (func $hidden (export "hidden") (result i32) (i32.const 7)) +) +` + +let wat = ` +(module + (import "m" "hidden" (func $imported (result i32))) + (func $local (result i32) (i32.const 11)) + (func $exported (export "exported") (result i32) (i32.const 13)) + (elem declare funcref (ref.func $imported) (ref.func $local) (ref.func $exported)) + (func (export "importedRef") (result funcref) (ref.func $imported)) + (func (export "localRef") (result funcref) (ref.func $local)) + (func (export "exportedRef") (result funcref) (ref.func $exported)) +) +` + +async function test() { + const { hidden } = (await instantiate(producerWat)).exports + const { importedRef, localRef, exportedRef, exported } = (await instantiate(wat, { m: { hidden } })).exports + + let imported = importedRef() + let local = localRef() + let exportedFromRef = exportedRef() + + for (let i = 0; i < wasmTestLoopCount; ++i) { + assert.eq(importedRef(), imported) + assert.eq(localRef(), local) + assert.eq(exportedRef(), exportedFromRef) + } + + assert.eq(imported === local, false) + assert.eq(local === exportedFromRef, false) + assert.eq(imported, hidden) + assert.eq(exportedFromRef, exported) + assert.eq(imported(), 7) + assert.eq(local(), 11) + assert.eq(exportedFromRef(), 13) + + fullGC() + assert.eq(importedRef(), imported) + assert.eq(localRef(), local) + assert.eq(exportedRef(), exported) +} + +await assert.asyncTest(test()) diff --git a/JSTests/wasm/stress/tail-call-unused-pins.js b/JSTests/wasm/stress/tail-call-unused-pins.js new file mode 100644 index 000000000000..fe5393ffe61d --- /dev/null +++ b/JSTests/wasm/stress/tail-call-unused-pins.js @@ -0,0 +1,50 @@ +//@ requireOptions("--useWasmFastMemory=true") +import { instantiate } from "../wabt-wrapper.js"; +import * as assert from "../assert.js"; + +const watA = ` +(module + (type $sig (func (param i32 i64))) + (import "e" "mem" (memory 1 1)) + (import "e" "nop" (func $nop)) + (table (export "tbl") 1 1 funcref) + (func (export "f") (param $do_call i32) (param $off i32) (param $val i64) + (call $nop) + (if (local.get $do_call) + (then (return_call_indirect (type $sig) + (local.get $off) (local.get $val) (i32.const 0)))))) +`; + +const watB = ` +(module + (import "e" "mem" (memory 1 1)) + (func (export "g") (param $off i32) (param $val i64) + (i64.store (local.get $off) (local.get $val)))) +`; + +async function test() { + const memA = createWebAssemblyMemoryWithMode({ initial: 1, maximum: 1 }, "Signaling"); + const memB = createWebAssemblyMemoryWithMode({ initial: 1, maximum: 1 }, "BoundsChecking"); + assert.eq(WebAssemblyMemoryMode(memA), "Signaling"); + assert.eq(WebAssemblyMemoryMode(memB), "BoundsChecking"); + + const instA = await instantiate(watA, { e: { mem: memA, nop: () => {} } }, { tail_call: true }); + const { f, tbl } = instA.exports; + + const instB = await instantiate(watB, { e: { mem: memB } }); + const { g } = instB.exports; + + assert.throws(() => g(0x20000, 0n), WebAssembly.RuntimeError, "Out of bounds memory access"); + + // Tier g into BBQ. IPInt's prologue reloads regCS4 on entry but BBQ does not. + for (let i = 0; i < wasmTestLoopCount; ++i) g(0, 0n); + + // Tier f to OMG without ever taking the tail-call branch. + for (let i = 0; i < wasmTestLoopCount; ++i) f(0, 0, 0n); + + tbl.set(0, g); + + assert.throws(() => f(1, 0x20000, 0n), WebAssembly.RuntimeError, "Out of bounds memory access"); +} + +await assert.asyncTest(test()); diff --git a/JSTests/wasm/stress/unreachable-end-if-no-else-widens-to-signature.js b/JSTests/wasm/stress/unreachable-end-if-no-else-widens-to-signature.js new file mode 100644 index 000000000000..73af41f67744 --- /dev/null +++ b/JSTests/wasm/stress/unreachable-end-if-no-else-widens-to-signature.js @@ -0,0 +1,75 @@ +// rdar://180535979 +// The unreachable End handler synthesizes an else for `if`-without-`else` and +// installs the saved if-param stack as the (reachable) else-arm result. Those +// values must be widened to the block's declared result types before they +// propagate to the parent stack: an unreachable then-arm may have `br 0`'d a +// value that only inhabits the wider result type. Without widening, BBQ's +// emitRefTestOrCast trusts the stale narrow type and elides the IsCell / +// IsWasmGCObject runtime checks. + +import * as assert from "../assert.js"; + +function uleb128(n) { const r = []; do { let b = n & 0x7f; n >>>= 7; if (n) b |= 0x80; r.push(b); } while (n); return r; } +function encodeString(s) { const b = []; for (let i = 0; i < s.length; i++) b.push(s.charCodeAt(i)); return [...uleb128(b.length), ...b]; } +function section(id, content) { return [id, ...uleb128(content.length), ...content]; } + +function buildModule() { + const typeSection = section(1, [ + 4, + 0x5F, 0x01, 0x7E, 0x01, // type 0: struct { i64 mut } + 0x60, 0x01, 0x64, 0x00, 0x01, 0x6E, // type 1: func (param (ref 0)) (result anyref) + 0x60, 0x03, 0x7F, 0x6F, 0x64, 0x00, 0x01, 0x7E, // type 2: func (i32, externref, (ref 0)) -> i64 + 0x60, 0x00, 0x01, 0x64, 0x00, // type 3: func () -> (ref 0) + ]); + const funcSection = section(3, [0x02, 0x02, 0x03]); + const exportSection = section(7, [0x02, + ...encodeString("test"), 0x00, 0x00, + ...encodeString("make"), 0x00, 0x01]); + + // (func $test (param $cond i32) (param $ext externref) (param $s (ref 0)) (result i64) + // local.get $s + // local.get $cond + // if (param (ref 0)) (result anyref) + // drop + // local.get $ext + // any.convert_extern + // br 0 ;; then-arm goes unreachable + // end ;; <- parseUnreachableExpression()::End, synthetic else + // ref.cast (ref 0) ;; must NOT elide IsCell / IsWasmGCObject checks + // struct.get 0 0) + const body0 = [ + 0x00, + 0x20, 0x02, + 0x20, 0x00, + 0x04, 0x01, + 0x1A, + 0x20, 0x01, + 0xFB, 0x1A, + 0x0C, 0x00, + 0x0B, + 0xFB, 0x16, 0x00, + 0xFB, 0x02, 0x00, 0x00, + 0x0B, + ]; + // (func $make (result (ref 0)) i64.const 0x1234 struct.new 0) + const body1 = [0x00, 0x42, 0xB4, 0x24, 0xFB, 0x00, 0x00, 0x0B]; + const codeSection = section(10, [0x02, + ...uleb128(body0.length), ...body0, + ...uleb128(body1.length), ...body1]); + return new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ...typeSection, ...funcSection, ...exportSection, ...codeSection]); +} + +const bytes = buildModule(); +assert.truthy(WebAssembly.validate(bytes)); +const instance = new WebAssembly.Instance(new WebAssembly.Module(bytes)); +const struct = instance.exports.make(); + +for (let i = 0; i < wasmTestLoopCount; ++i) { + // cond == 0: synthetic else delivers the (ref 0) param; ref.cast succeeds. + assert.eq(instance.exports.test(0, null, struct), 0x1234n); + // cond == 1: then-arm br's an anyref-wrapped JS number to the if's + // continuation. The post-end value is statically anyref, so ref.cast must + // perform the full runtime check and trap. + assert.throws(() => instance.exports.test(1, 1.5, struct), WebAssembly.RuntimeError, "ref.cast failed to cast reference to target heap type"); +} diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations index e649b41a63ee..7fec63724abe 100644 --- a/LayoutTests/TestExpectations +++ b/LayoutTests/TestExpectations @@ -1370,7 +1370,6 @@ webkit.org/b/309872 imported/w3c/web-platform-tests/permissions-policy/reporting webkit.org/b/182292 imported/w3c/web-platform-tests/css/cssom-view/scrollingElement-quirks-dynamic-001.html [ ImageOnlyFailure ] webkit.org/b/182292 imported/w3c/web-platform-tests/css/cssom-view/scrollingElement-quirks-dynamic-002.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-015.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm [ Skip ] imported/w3c/web-platform-tests/mediacapture-fromelement/capture.html [ Failure ] imported/w3c/web-platform-tests/mediacapture-fromelement/ended.html [ Failure ] @@ -4186,10 +4185,6 @@ imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-021. imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-022.tentative.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-023.tentative.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-024.tentative.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-008.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-011.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-012.html [ ImageOnlyFailure ] @@ -4205,13 +4200,6 @@ imported/w3c/web-platform-tests/css/css-overflow/overflow-canvas.html [ ImageOnl imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-border-radius-002.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-border-radius.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/flex-column-container-with-scrollable-descendant.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/flex-container-multiple-items-with-scrollable-descendant.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/flex-container-with-scrollable-descendant.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/flex-nested-container-with-scrollable-descendant.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/grid-container-with-scrollable-descendant.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/grid-nested-container-with-scrollable-descendant.html [ ImageOnlyFailure ] - # Tests that failed on the 2026-02-02 import of css-overflow imported/w3c/web-platform-tests/css/css-overflow/clip-008.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/column-style-change-triggers-relayout.html [ ImageOnlyFailure ] @@ -4233,7 +4221,6 @@ imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-027.h imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-028.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-029.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-030.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032.tentative.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-repaint-003.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/continue-001.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/discard/discard-multicol-001.html [ ImageOnlyFailure ] @@ -4244,13 +4231,10 @@ imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-003.html imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-007.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-008.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-009.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-011.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-019.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-021.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-030.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-033.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-034.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-035.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-036.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-037.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-038.html [ ImageOnlyFailure ] @@ -4310,21 +4294,69 @@ imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixe imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-015.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-016.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-017.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004.tentative.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-008.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-text-overflow-string-003.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-024.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-036.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-040.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-045.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-048.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-050.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-052.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-053.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html [ ImageOnlyFailure ] + +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-033.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-035.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-036.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-037.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-039.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-040.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-041.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-002.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-003.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-004.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-002.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-033.html [ Skip ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-041.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-042.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-043.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-044.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-045.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-046.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-047.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-bfc.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-011.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-editable-div-with-caret.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-016.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-018.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-019.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-020.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-021.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-022.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-024.tentative.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-025.tentative.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-026.tentative.html [ ImageOnlyFailure ] + +imported/w3c/web-platform-tests/css/css-overflow/overflow-video-hidden.html [ Skip ] +imported/w3c/web-platform-tests/css/css-overflow/unicode-bidi-plaintext-scroll-direction.html [ Skip ] # Fail to run due to rdar://169497013 imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-026.html [ Skip ] @@ -4875,9 +4907,9 @@ webkit.org/b/244813 imported/w3c/web-platform-tests/css/css-text-decor/text-deco imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-thickness-length-rounding-001.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-thickness-length-rounding-002.html [ ImageOnlyFailure ] -# fractional-position endpoint rounds up to a device pixel -webkit.org/b/244813 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-009.html [ ImageOnlyFailure ] -webkit.org/b/244813 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-014.html [ ImageOnlyFailure ] +# Not a text-decoration-inset bug: the test sets unprefixed 'box-decoration-break', which WebKit does not support (only -webkit-box-decoration-break), so the box is sliced rather than cloned. +# The test passes once the declaration is prefixed. +imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029.html [ ImageOnlyFailure ] # Not a text-decoration-inset bug: a pre-existing ~1px vertical decoration-position difference in a # columns:2 multicol context with inline vertical borders. Reproduces with the feature disabled. @@ -5386,18 +5418,14 @@ webkit.org/b/299202 imported/w3c/web-platform-tests/css/css-writing-modes/wm-pro webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/appearance-menulist-button-002.tentative.html [ ImageOnlyFailure ] webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/outline-025.html [ ImageOnlyFailure ] webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/outline-026.html [ ImageOnlyFailure ] -webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/text-overflow-ruby.html [ ImageOnlyFailure ] -webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/text-overflow-021.html [ ImageOnlyFailure ] webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/webkit-appearance-menulist-button-002.tentative.html [ ImageOnlyFailure ] webkit.org/b/214299 imported/w3c/web-platform-tests/css/css-ui/resize-child-will-change-transform.html [ ImageOnlyFailure ] webkit.org/b/279302 imported/w3c/web-platform-tests/css/css-ui/negative-outline-offset.html [ ImageOnlyFailure ] -webkit.org/b/279302 imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html [ ImageOnlyFailure ] # New failure after import of css/css-ui (2026-07): webkit.org/b/320474 imported/w3c/web-platform-tests/css/css-ui/compute-kind-widget-no-fallback-props-001.html [ ImageOnlyFailure ] webkit.org/b/320474 imported/w3c/web-platform-tests/css/css-ui/resize-textarea-relative-to-right-001.tentative.html [ Pass Failure ] -webkit.org/b/320474 imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-multiline-001.html [ ImageOnlyFailure ] # Missing CSS-UI-4 caret properties: webkit.org/b/319405 imported/w3c/web-platform-tests/css/css-ui/caret-color-bar-shape-text-color.html [ ImageOnlyFailure ] @@ -5429,15 +5457,23 @@ webkit.org/b/319405 imported/w3c/web-platform-tests/css/css-ui/caret-shape-block webkit.org/b/319405 imported/w3c/web-platform-tests/css/css-ui/caret-shape-block-zoom.html [ ImageOnlyFailure ] webkit.org/b/319405 imported/w3c/web-platform-tests/css/css-ui/caret-shape-underscore-001.html [ ImageOnlyFailure ] -# Missing text-overflow: -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-001.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-002.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-003.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-004.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-005.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-006.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-007.html [ ImageOnlyFailure ] -webkit.org/b/27545 imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-008.html [ ImageOnlyFailure ] +# text-overflow failures +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ruby.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-021.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-028.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-multiline-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-editing-input.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-vertical-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-vertical-rtl-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-rtl-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-lr-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-lr-rtl-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-rl-001.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-rl-rtl-001.html [ ImageOnlyFailure ] + +# text-overflow should take in account unicode-bidi to determine ellipsis position. +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-008.html webkit.org/b/214387 imported/w3c/web-platform-tests/svg/animations/seeking-events-4.html [ Pass Failure ] @@ -5725,16 +5761,6 @@ webkit.org/b/277262 [ Debug ] imported/w3c/web-platform-tests/css/css-multicol/m # -- End CSS multicol -- # -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-editing-input.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-vertical-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-ellipsis-vertical-rtl-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-rtl-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-lr-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-lr-rtl-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-rl-001.html [ ImageOnlyFailure ] -webkit.org/b/214459 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-scroll-vertical-rl-rtl-001.html [ ImageOnlyFailure ] - webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/active-selection-051.html [ ImageOnlyFailure ] webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/active-selection-052.html [ ImageOnlyFailure ] webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/active-selection-053.html [ ImageOnlyFailure ] @@ -5750,13 +5776,8 @@ webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/first-line-op webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/grammar-error-001.html [ ImageOnlyFailure ] webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-content-010.html [ ImageOnlyFailure ] webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-content-012.html [ ImageOnlyFailure ] -webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-content-014.html [ ImageOnlyFailure ] webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-content-017.html [ ImageOnlyFailure ] webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-content-018.html [ ImageOnlyFailure ] -# Inside ::marker content is laid out as an inline-block whose block-size drives the line box, so it -# does not yet match the line metrics of a native inside marker (shared root cause with marker-content-012). -webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-font-variant-numeric-default.html [ ImageOnlyFailure ] -webkit.org/b/204163 imported/w3c/web-platform-tests/css/css-pseudo/marker-font-variant-numeric-normal.html [ ImageOnlyFailure ] webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/marker-list-style-position.html [ ImageOnlyFailure ] webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/marker-unicode-bidi-normal.html [ ImageOnlyFailure ] webkit.org/b/214461 imported/w3c/web-platform-tests/css/css-pseudo/spelling-error-001.html [ ImageOnlyFailure ] @@ -6247,9 +6268,6 @@ imported/w3c/web-platform-tests/trusted-types/should-trusted-type-policy-creatio webkit.org/b/281223 imported/w3c/web-platform-tests/dom/nodes/moveBefore/focus-preserve-render.html [ Skip ] webkit.org/b/281223 imported/w3c/web-platform-tests/dom/nodes/moveBefore/moveBefore-option-recalc-style.html [ Skip ] -# Flaky crash. -webkit.org/b/315031 imported/w3c/web-platform-tests/dom/nodes/moveBefore/throws-exception.html [ Skip ] - # Flaky. imported/w3c/web-platform-tests/dom/nodes/insertion-removing-steps/Node-appendChild-script-and-default-style-meta-from-fragment.html [ Skip ] @@ -6753,9 +6771,7 @@ webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-stroke-from-border.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-two-shapes-shadow.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-outline-double.html [ ImageOnlyFailure ] -webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-video-overflow.html [ ImageOnlyFailure Pass ] -webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-clips-background.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-collapsed-shape-clips-background.html [ ImageOnlyFailure ] webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/border-shape/border-shape-geometry-box.html [ ImageOnlyFailure ] diff --git a/LayoutTests/accessibility/isolated-tree/empty-final-line-range-expected.txt b/LayoutTests/accessibility/isolated-tree/empty-final-line-range-expected.txt new file mode 100644 index 000000000000..db2ef58f8e3e --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/empty-final-line-range-expected.txt @@ -0,0 +1,10 @@ +This test ensures the line at a text control's last text position is its empty final line. + +PASS: textarea.stringForTextMarkerRange(lineRange) === '' +PASS: textarea.textMarkerRangeLength(lineRange) === 0 +PASS: lineStart.isEqual(lastMarker) === true + +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/accessibility/isolated-tree/empty-final-line-range.html b/LayoutTests/accessibility/isolated-tree/empty-final-line-range.html new file mode 100644 index 000000000000..1ebc94777c4b --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/empty-final-line-range.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + diff --git a/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary-expected.txt b/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary-expected.txt new file mode 100644 index 000000000000..594a889cb7e9 --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary-expected.txt @@ -0,0 +1,100 @@ +Asserts that AXReplaceRangeWithText writes at the character index it is given, including the +index that starts a block, and clamps a range running past the end of the value to the end +rather than writing at the current selection. + +block ending in
, index starting the next block: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +block without a trailing
: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +
-separated lines: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +one line, index starting the blank second line: value "alpha\n\n", replacing {6, 0} +PASS: axField.replaceTextInRange("Y", 6, 0) === true +PASS: textOf(field) === "alpha\nY\n" +PASS: textOf(bystander) === "bystander" + +two blocks ending in
: value "alpha\nbravo\ncharlie\n\n", replacing {20, 0} +PASS: axField.replaceTextInRange("Y", 20, 0) === true +PASS: textOf(field) === "alpha\nbravo\ncharlie\nY\n" +PASS: textOf(bystander) === "bystander" + +interior index: value "alpha\nbravo\n\n", replacing {6, 0} +PASS: axField.replaceTextInRange("Y", 6, 0) === true +PASS: textOf(field) === "alpha\nYbravo\n\n" +PASS: textOf(bystander) === "bystander" + +replacing a run of characters: value "alpha\nbravo\n\n", replacing {6, 5} +PASS: axField.replaceTextInRange("Y", 6, 5) === true +PASS: textOf(field) === "alpha\nY\n\n" +PASS: textOf(bystander) === "bystander" + +field with no text: value "", replacing {0, 0} +PASS: axField.replaceTextInRange("Y", 0, 0) === true +PASS: textOf(field) === "Y" +PASS: textOf(bystander) === "bystander" + +textarea, index starting the blank final line: value "alpha\nbravo\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY" +PASS: textOf(bystander) === "bystander" + +location one past the end of the value: value "alpha\nbravo\n\n", replacing {14, 0} +PASS: axField.replaceTextInRange("Y", 14, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +location far past the end of the value: value "alpha\nbravo\n\n", replacing {99, 0} +PASS: axField.replaceTextInRange("Y", 99, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +length running past the end of the value: value "alpha\nbravo\n\n", replacing {6, 99} +PASS: axField.replaceTextInRange("Y", 6, 99) === true +PASS: textOf(field) === "alpha\nY\n" +PASS: textOf(bystander) === "bystander" + + +PASS successfullyParsed is true + +TEST COMPLETE +alpha +bravo +Y +alpha +bravo +Y +alpha +bravo +Y +alpha +Y +alpha +bravo +charlie +Y +alpha +bravo +Y +alpha +bravo +Y +alpha +Y +alpha +Ybravo + +alpha +Y + +Y + +bystander diff --git a/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary.html b/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary.html new file mode 100644 index 000000000000..90b842f40a78 --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/mac/replace-range-at-block-boundary.html @@ -0,0 +1,123 @@ + + + + + + + + + +
alpha
bravo

+ +
alpha
bravo

+
alpha
bravo

+ +
alpha

+ +
alpha
bravo
charlie

+ +
alpha
bravo

+
alpha
bravo

+
alpha
bravo

+ +
alpha
bravo

+
alpha
bravo

+ +
+ + + +
bystander
+ + + + diff --git a/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control-expected.txt b/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control-expected.txt new file mode 100644 index 000000000000..8dfd3e1f2130 --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control-expected.txt @@ -0,0 +1,31 @@ +Asserts that AXTextMarkerRangeForUIElement covers a text control's value rather than the +control as a single replaced object. A genuinely replaced element still answers with itself. + +textarea: +PASS: webArea.stringForTextMarkerRange(range) === "alpha\nbravo\n" +PASS: webArea.textMarkerRangeLength(range) === 12 + +text input: +PASS: webArea.stringForTextMarkerRange(range) === "alpha bravo" +PASS: webArea.textMarkerRangeLength(range) === 11 + +search input: +PASS: webArea.stringForTextMarkerRange(range) === "alpha bravo" +PASS: webArea.textMarkerRangeLength(range) === 11 + +contenteditable: +PASS: webArea.stringForTextMarkerRange(range) === "alpha\nbravo\n" +PASS: webArea.textMarkerRangeLength(range) === 12 + +image: +PASS: webArea.stringForTextMarkerRange(range) === "" +PASS: webArea.textMarkerRangeLength(range) === 1 + + +PASS successfullyParsed is true + +TEST COMPLETE + +alpha +bravo + diff --git a/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control.html b/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control.html new file mode 100644 index 000000000000..afd35d80208e --- /dev/null +++ b/LayoutTests/accessibility/isolated-tree/mac/text-marker-range-for-text-control.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + +
alpha
bravo
+A cake + + + + diff --git a/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space-expected.txt b/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space-expected.txt new file mode 100644 index 000000000000..66ef3fc2be08 --- /dev/null +++ b/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space-expected.txt @@ -0,0 +1,14 @@ +This test ensures a line ended by soft wrapping excludes the space at the wrap point. + +PASS: lineText(1) === 'aaa' +PASS: lineText(2) === 'bbb' +PASS: webArea.textMarkerRangeLength(lineRange(1)) === 3 +PASS: lineText(3) === 'ccc' +PASS: lineText(4) === 'ddd' +PASS: lineText(5) === 'eee' +PASS: lineText(6) === 'fff' + +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space.html b/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space.html new file mode 100644 index 000000000000..47e6d9557046 --- /dev/null +++ b/LayoutTests/accessibility/mac/line-range-at-soft-break-excludes-space.html @@ -0,0 +1,52 @@ + + + + + + + + + +

aaa bbb

+

ccc ddd

+

eee fff

+ + + + diff --git a/LayoutTests/accessibility/mac/replace-range-at-block-boundary-expected.txt b/LayoutTests/accessibility/mac/replace-range-at-block-boundary-expected.txt new file mode 100644 index 000000000000..594a889cb7e9 --- /dev/null +++ b/LayoutTests/accessibility/mac/replace-range-at-block-boundary-expected.txt @@ -0,0 +1,100 @@ +Asserts that AXReplaceRangeWithText writes at the character index it is given, including the +index that starts a block, and clamps a range running past the end of the value to the end +rather than writing at the current selection. + +block ending in
, index starting the next block: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +block without a trailing
: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +
-separated lines: value "alpha\nbravo\n\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +one line, index starting the blank second line: value "alpha\n\n", replacing {6, 0} +PASS: axField.replaceTextInRange("Y", 6, 0) === true +PASS: textOf(field) === "alpha\nY\n" +PASS: textOf(bystander) === "bystander" + +two blocks ending in
: value "alpha\nbravo\ncharlie\n\n", replacing {20, 0} +PASS: axField.replaceTextInRange("Y", 20, 0) === true +PASS: textOf(field) === "alpha\nbravo\ncharlie\nY\n" +PASS: textOf(bystander) === "bystander" + +interior index: value "alpha\nbravo\n\n", replacing {6, 0} +PASS: axField.replaceTextInRange("Y", 6, 0) === true +PASS: textOf(field) === "alpha\nYbravo\n\n" +PASS: textOf(bystander) === "bystander" + +replacing a run of characters: value "alpha\nbravo\n\n", replacing {6, 5} +PASS: axField.replaceTextInRange("Y", 6, 5) === true +PASS: textOf(field) === "alpha\nY\n\n" +PASS: textOf(bystander) === "bystander" + +field with no text: value "", replacing {0, 0} +PASS: axField.replaceTextInRange("Y", 0, 0) === true +PASS: textOf(field) === "Y" +PASS: textOf(bystander) === "bystander" + +textarea, index starting the blank final line: value "alpha\nbravo\n", replacing {12, 0} +PASS: axField.replaceTextInRange("Y", 12, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY" +PASS: textOf(bystander) === "bystander" + +location one past the end of the value: value "alpha\nbravo\n\n", replacing {14, 0} +PASS: axField.replaceTextInRange("Y", 14, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +location far past the end of the value: value "alpha\nbravo\n\n", replacing {99, 0} +PASS: axField.replaceTextInRange("Y", 99, 0) === true +PASS: textOf(field) === "alpha\nbravo\nY\n" +PASS: textOf(bystander) === "bystander" + +length running past the end of the value: value "alpha\nbravo\n\n", replacing {6, 99} +PASS: axField.replaceTextInRange("Y", 6, 99) === true +PASS: textOf(field) === "alpha\nY\n" +PASS: textOf(bystander) === "bystander" + + +PASS successfullyParsed is true + +TEST COMPLETE +alpha +bravo +Y +alpha +bravo +Y +alpha +bravo +Y +alpha +Y +alpha +bravo +charlie +Y +alpha +bravo +Y +alpha +bravo +Y +alpha +Y +alpha +Ybravo + +alpha +Y + +Y + +bystander diff --git a/LayoutTests/accessibility/mac/replace-range-at-block-boundary.html b/LayoutTests/accessibility/mac/replace-range-at-block-boundary.html new file mode 100644 index 000000000000..595a1fa8fae5 --- /dev/null +++ b/LayoutTests/accessibility/mac/replace-range-at-block-boundary.html @@ -0,0 +1,123 @@ + + + + + + + + + +
alpha
bravo

+ +
alpha
bravo

+
alpha
bravo

+ +
alpha

+ +
alpha
bravo
charlie

+ +
alpha
bravo

+
alpha
bravo

+
alpha
bravo

+ +
alpha
bravo

+
alpha
bravo

+ +
+ + + +
bystander
+ + + + diff --git a/LayoutTests/accessibility/mac/text-marker-range-for-text-control-expected.txt b/LayoutTests/accessibility/mac/text-marker-range-for-text-control-expected.txt new file mode 100644 index 000000000000..8dfd3e1f2130 --- /dev/null +++ b/LayoutTests/accessibility/mac/text-marker-range-for-text-control-expected.txt @@ -0,0 +1,31 @@ +Asserts that AXTextMarkerRangeForUIElement covers a text control's value rather than the +control as a single replaced object. A genuinely replaced element still answers with itself. + +textarea: +PASS: webArea.stringForTextMarkerRange(range) === "alpha\nbravo\n" +PASS: webArea.textMarkerRangeLength(range) === 12 + +text input: +PASS: webArea.stringForTextMarkerRange(range) === "alpha bravo" +PASS: webArea.textMarkerRangeLength(range) === 11 + +search input: +PASS: webArea.stringForTextMarkerRange(range) === "alpha bravo" +PASS: webArea.textMarkerRangeLength(range) === 11 + +contenteditable: +PASS: webArea.stringForTextMarkerRange(range) === "alpha\nbravo\n" +PASS: webArea.textMarkerRangeLength(range) === 12 + +image: +PASS: webArea.stringForTextMarkerRange(range) === "" +PASS: webArea.textMarkerRangeLength(range) === 1 + + +PASS successfullyParsed is true + +TEST COMPLETE + +alpha +bravo + diff --git a/LayoutTests/accessibility/mac/text-marker-range-for-text-control.html b/LayoutTests/accessibility/mac/text-marker-range-for-text-control.html new file mode 100644 index 000000000000..891a8b1b022d --- /dev/null +++ b/LayoutTests/accessibility/mac/text-marker-range-for-text-control.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + +
alpha
bravo
+A cake + + + + diff --git a/LayoutTests/fast/canvas/canvas-filter-fillText-crash-expected.txt b/LayoutTests/fast/canvas/canvas-filter-fillText-crash-expected.txt new file mode 100644 index 000000000000..49004868ff5d --- /dev/null +++ b/LayoutTests/fast/canvas/canvas-filter-fillText-crash-expected.txt @@ -0,0 +1,3 @@ +This test passes if it does not crash. + + diff --git a/LayoutTests/fast/canvas/canvas-filter-fillText-crash.html b/LayoutTests/fast/canvas/canvas-filter-fillText-crash.html new file mode 100644 index 000000000000..6cd77d35cdbb --- /dev/null +++ b/LayoutTests/fast/canvas/canvas-filter-fillText-crash.html @@ -0,0 +1,20 @@ + + + + +

This test passes if it does not crash.

+ + + diff --git a/LayoutTests/fast/images/animated-image-mp4-crash.html b/LayoutTests/fast/images/animated-image-mp4-crash.html index 4a22c794a2b0..931248a03b97 100644 --- a/LayoutTests/fast/images/animated-image-mp4-crash.html +++ b/LayoutTests/fast/images/animated-image-mp4-crash.html @@ -13,7 +13,9 @@ return new Promise(resolve => { const image = document.querySelector('img'); image.src = src; - return image.decode().then(() => { resolve(image); }); + // The file is malformed on purpose, so decode() is allowed to reject. This test + // only checks that loading it does not crash, and hangs if the promise never settles. + return image.decode().then(() => { resolve(image); }, () => { resolve(image); }); }); } diff --git a/LayoutTests/fast/images/apng-acTL-frame-count-overflow-expected.txt b/LayoutTests/fast/images/apng-acTL-frame-count-overflow-expected.txt new file mode 100644 index 000000000000..6c9c792760f6 --- /dev/null +++ b/LayoutTests/fast/images/apng-acTL-frame-count-overflow-expected.txt @@ -0,0 +1,4 @@ +An APNG whose acTL declares more frames than PNGImageDecoder accepts must not report that count to its callers, which size per-frame containers from it. + +PASS + diff --git a/LayoutTests/fast/images/apng-acTL-frame-count-overflow.html b/LayoutTests/fast/images/apng-acTL-frame-count-overflow.html new file mode 100644 index 000000000000..ca8d87c092d5 --- /dev/null +++ b/LayoutTests/fast/images/apng-acTL-frame-count-overflow.html @@ -0,0 +1,36 @@ + +

An APNG whose acTL declares more frames than PNGImageDecoder accepts must not report that count +to its callers, which size per-frame containers from it.

+
PASS
+ + diff --git a/LayoutTests/fast/images/apng-acTL-zero-frame-count-expected.txt b/LayoutTests/fast/images/apng-acTL-zero-frame-count-expected.txt new file mode 100644 index 000000000000..4c4ad20e177b --- /dev/null +++ b/LayoutTests/fast/images/apng-acTL-zero-frame-count-expected.txt @@ -0,0 +1,3 @@ +An APNG whose acTL declares zero frames is not an animation, so the default image must still decode as a static PNG rather than being reported as a zero-frame image and dropped. + +PASS diff --git a/LayoutTests/fast/images/apng-acTL-zero-frame-count.html b/LayoutTests/fast/images/apng-acTL-zero-frame-count.html new file mode 100644 index 000000000000..28285e3314f3 --- /dev/null +++ b/LayoutTests/fast/images/apng-acTL-zero-frame-count.html @@ -0,0 +1,39 @@ + +

An APNG whose acTL declares zero frames is not an animation, so the default image must still +decode as a static PNG rather than being reported as a zero-frame image and dropped.

+
PASS
+ diff --git a/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction-expected.txt b/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction-expected.txt new file mode 100644 index 000000000000..d279fbdf979d --- /dev/null +++ b/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction-expected.txt @@ -0,0 +1,4 @@ +Dropping decoded frames and then decoding again must not leave a frame reading a cleared frame's backing store. The test passes if the web process survives. + +PASS + diff --git a/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction.html b/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction.html new file mode 100644 index 000000000000..6b4f64838736 --- /dev/null +++ b/LayoutTests/fast/images/apng-decode-after-frame-cache-eviction.html @@ -0,0 +1,41 @@ + +

Dropping decoded frames and then decoding again must not leave a frame reading a cleared frame's +backing store. The test passes if the web process survives.

+
PASS
+ + diff --git a/LayoutTests/fast/images/apng-icc-frame-right-half-expected.html b/LayoutTests/fast/images/apng-icc-frame-right-half-expected.html new file mode 100644 index 000000000000..0af273762072 --- /dev/null +++ b/LayoutTests/fast/images/apng-icc-frame-right-half-expected.html @@ -0,0 +1,6 @@ + + + diff --git a/LayoutTests/fast/images/apng-icc-frame-right-half.html b/LayoutTests/fast/images/apng-icc-frame-right-half.html new file mode 100644 index 000000000000..fcffb7d65d5e --- /dev/null +++ b/LayoutTests/fast/images/apng-icc-frame-right-half.html @@ -0,0 +1,19 @@ + + + + + diff --git a/LayoutTests/fast/images/resources/apng-acTL-frame-count-overflow.png b/LayoutTests/fast/images/resources/apng-acTL-frame-count-overflow.png new file mode 100644 index 000000000000..7510af8a337a Binary files /dev/null and b/LayoutTests/fast/images/resources/apng-acTL-frame-count-overflow.png differ diff --git a/LayoutTests/fast/images/resources/apng-acTL-zero-frame-count.png b/LayoutTests/fast/images/resources/apng-acTL-zero-frame-count.png new file mode 100644 index 000000000000..6da166756ef4 Binary files /dev/null and b/LayoutTests/fast/images/resources/apng-acTL-zero-frame-count.png differ diff --git a/LayoutTests/fast/images/resources/apng-frame-cache-eviction.png b/LayoutTests/fast/images/resources/apng-frame-cache-eviction.png new file mode 100644 index 000000000000..3e5f7b2446a3 Binary files /dev/null and b/LayoutTests/fast/images/resources/apng-frame-cache-eviction.png differ diff --git a/LayoutTests/fast/images/resources/apng-icc-frame-right-half-reference.png b/LayoutTests/fast/images/resources/apng-icc-frame-right-half-reference.png new file mode 100644 index 000000000000..0ec71fb1b99e Binary files /dev/null and b/LayoutTests/fast/images/resources/apng-icc-frame-right-half-reference.png differ diff --git a/LayoutTests/fast/images/resources/apng-icc-frame-right-half.png b/LayoutTests/fast/images/resources/apng-icc-frame-right-half.png new file mode 100644 index 000000000000..0fb539f9d3ad Binary files /dev/null and b/LayoutTests/fast/images/resources/apng-icc-frame-right-half.png differ diff --git a/LayoutTests/fast/webgpu/index-buffer-cache-invalidation-expected.txt b/LayoutTests/fast/webgpu/index-buffer-cache-invalidation-expected.txt new file mode 100644 index 000000000000..9f9c2060a4c2 --- /dev/null +++ b/LayoutTests/fast/webgpu/index-buffer-cache-invalidation-expected.txt @@ -0,0 +1,2 @@ +PASS - no GPU OOB read + diff --git a/LayoutTests/fast/webgpu/index-buffer-cache-invalidation.html b/LayoutTests/fast/webgpu/index-buffer-cache-invalidation.html new file mode 100644 index 000000000000..d0793b422caf --- /dev/null +++ b/LayoutTests/fast/webgpu/index-buffer-cache-invalidation.html @@ -0,0 +1,93 @@ + +

diff --git a/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash-expected.txt b/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash-expected.txt
new file mode 100644
index 000000000000..2085c15f7edf
--- /dev/null
+++ b/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash-expected.txt
@@ -0,0 +1,3 @@
+An ICO whose PNG sub-image has only partly arrived must not be asked for a frame buffer before the sub-decoder has parsed its own header. The test passes unless a crash happens.
+
+
diff --git a/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash.html b/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash.html
new file mode 100644
index 000000000000..8c53d6076491
--- /dev/null
+++ b/LayoutTests/http/tests/images/ico-png-subimage-partial-load-crash.html
@@ -0,0 +1,38 @@
+
+

An ICO whose PNG sub-image has only partly arrived must not be asked for a frame buffer before +the sub-decoder has parsed its own header. The test passes unless a crash happens.

+ + diff --git a/LayoutTests/http/tests/images/resources/ico-png-subimage.ico b/LayoutTests/http/tests/images/resources/ico-png-subimage.ico new file mode 100644 index 000000000000..ace422424d9b Binary files /dev/null and b/LayoutTests/http/tests/images/resources/ico-png-subimage.ico differ diff --git a/LayoutTests/imported/w3c/resources/resource-files.json b/LayoutTests/imported/w3c/resources/resource-files.json index 92e97d0cd3a5..de0958ad2ab8 100644 --- a/LayoutTests/imported/w3c/resources/resource-files.json +++ b/LayoutTests/imported/w3c/resources/resource-files.json @@ -7231,6 +7231,8 @@ "web-platform-tests/css/css-nesting/nesting-basic-ref.html", "web-platform-tests/css/css-nesting/supports-is-consistent-ref.html", "web-platform-tests/css/css-nesting/supports-rule-ref.html", + "web-platform-tests/css/css-overflow/abspos-shrink-to-fit-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/button-with-scrollable-descendant-ref.html", "web-platform-tests/css/css-overflow/clip-001-ref.html", "web-platform-tests/css/css-overflow/clip-002-ref.html", "web-platform-tests/css/css-overflow/clip-003-ref.html", @@ -7239,12 +7241,24 @@ "web-platform-tests/css/css-overflow/clipped-scroller-add-content-ref.html", "web-platform-tests/css/css-overflow/display-flex-svg-overflow-default-ref.html", "web-platform-tests/css/css-overflow/document-element-overflow-hidden-scroll-ref.html", + "web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002-ref.html", + "web-platform-tests/css/css-overflow/fit-content-textarea-with-scrollbar-ref.html", + "web-platform-tests/css/css-overflow/flex-column-container-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/flex-container-multiple-items-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/flex-container-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/flex-nested-container-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/float-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/grid-container-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/grid-nested-container-with-scrollable-descendant-ref.html", "web-platform-tests/css/css-overflow/incremental-scroll-002-ref.html", "web-platform-tests/css/css-overflow/incremental-scroll-ref.html", + "web-platform-tests/css/css-overflow/inline-block-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-crash-001.html", "web-platform-tests/css/css-overflow/line-clamp/discard/reference/discard-multicol-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/discard/reference/discard-multicol-002-ref.html", "web-platform-tests/css/css-overflow/line-clamp/discard/reference/discard-multicol-003-ref.html", "web-platform-tests/css/css-overflow/line-clamp/discard/reference/discard-multicol-004-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/line-clamp-bfc-ref.html", "web-platform-tests/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-002-ref.html", @@ -7268,6 +7282,14 @@ "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-029-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-031-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-032-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-034-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-035-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-038-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-039-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-041-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-002-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-003-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-004-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-002-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-003-ref.html", @@ -7285,6 +7307,8 @@ "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-027-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-028-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-029-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-039-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-041-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-002-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-005-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html", @@ -7307,6 +7331,11 @@ "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-039-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-040-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-041-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-043-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-044-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-045-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-046-ref.html", + "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-047-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-003-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-005-ref.html", @@ -7330,9 +7359,7 @@ "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-abspos-023-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html", - "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html", - "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-text-overflow-string-003-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-001-ref.html", @@ -7380,6 +7407,14 @@ "web-platform-tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-block-in-inline-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-dynamic-001-ref.html", "web-platform-tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-with-line-height-ref.html", + "web-platform-tests/css/css-overflow/max-content-nested-textarea-with-scrollbar-ref.html", + "web-platform-tests/css/css-overflow/max-content-textarea-with-scrollbar-ref.html", + "web-platform-tests/css/css-overflow/max-content-with-float-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/max-content-with-multiple-scrollable-descendants-ref.html", + "web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant-vertical-rl-ref.html", + "web-platform-tests/css/css-overflow/min-content-textarea-with-scrollbar-ref.html", + "web-platform-tests/css/css-overflow/orthogonal-writing-mode-with-scrollable-descendant-ref.html", "web-platform-tests/css/css-overflow/overflow-alignment-001-ref.html", "web-platform-tests/css/css-overflow/overflow-alignment-002-ref.html", "web-platform-tests/css/css-overflow/overflow-alignment-block-001.html", @@ -7439,6 +7474,7 @@ "web-platform-tests/css/css-overflow/overflow-clip-transform-001-ref.html", "web-platform-tests/css/css-overflow/overflow-clip-x-visible-y-svg-ref.html", "web-platform-tests/css/css-overflow/overflow-clip-y-visible-x-svg-ref.html", + "web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-ref.html", "web-platform-tests/css/css-overflow/overflow-img-display-table-ref.html", "web-platform-tests/css/css-overflow/overflow-img-object-position-ref.html", "web-platform-tests/css/css-overflow/overflow-img-ref.html", @@ -7452,6 +7488,7 @@ "web-platform-tests/css/css-overflow/overflow-scroll-resize-visibility-hidden-ref.html", "web-platform-tests/css/css-overflow/overflow-video-ref.html", "web-platform-tests/css/css-overflow/paint-containment-svg-ref.html", + "web-platform-tests/css/css-overflow/reference/before-after-pseudo-element-scrolling-ref.html", "web-platform-tests/css/css-overflow/reference/input-scrollable-region-001-ref.html", "web-platform-tests/css/css-overflow/reference/overflow-body-no-propagation-ref.html", "web-platform-tests/css/css-overflow/reference/overflow-body-propagation-ref.html", @@ -7459,15 +7496,53 @@ "web-platform-tests/css/css-overflow/reference/overflow-inline-block-with-opacity-ref.html", "web-platform-tests/css/css-overflow/reference/overflow-recalc-001-ref.html", "web-platform-tests/css/css-overflow/reference/ref-if-there-is-no-red.xht", + "web-platform-tests/css/css-overflow/reference/text-overflow-001-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-002-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-005-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-006-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-008-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-012-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-013-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-016-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-021-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-022-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-027-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-028-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-029-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-030-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-change-color-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-002-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-editable-div-with-caret-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-indent-001-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-multiline-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-rtl-001-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-textarea-with-caret-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-vertical-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-vertical-rtl-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-scroll-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-scroll-rtl-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-scroll-vertical-lr-001-ref.html", "web-platform-tests/css/css-overflow/reference/text-overflow-scroll-vertical-lr-rtl-001-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-001-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-002-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-003-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-004-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-005-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-006-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-007-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-008-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-009-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-010-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-011-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-012-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-013-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-014-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-015-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-016-ref.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-024-ref.tentative.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-025-ref.tentative.html", + "web-platform-tests/css/css-overflow/reference/text-overflow-string-026-ref.tentative.html", "web-platform-tests/css/css-overflow/rounded-overflow-clip-visible-ref.html", "web-platform-tests/css/css-overflow/rounded-overflow-visible-clip-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/column-scroll-marker-001-ref.html", @@ -7480,6 +7555,7 @@ "web-platform-tests/css/css-overflow/scroll-markers/root-scroll-button-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/root-scroll-marker-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/scroll-button-on-object-ref.html", + "web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/scroll-buttons-001-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/scroll-buttons-appearance-ref.html", "web-platform-tests/css/css-overflow/scroll-markers/scroll-buttons-disabled-ref.html", @@ -7544,8 +7620,19 @@ "web-platform-tests/css/css-overflow/scrollbar-large-scale-in-iframe-ref.html", "web-platform-tests/css/css-overflow/scrollbars-chrome-bug-001-ref.html", "web-platform-tests/css/css-overflow/select-size-overflow-001-ref.html", + "web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-ref.html", + "web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-ref.html", + "web-platform-tests/css/css-overflow/table-max-content-with-scrollable-descendant-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-024-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-025-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-026-ref.html", "web-platform-tests/css/css-overflow/text-overflow-ellipsis-003-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-ellipsis-changing-scroll-ref.html", "web-platform-tests/css/css-overflow/text-overflow-ellipsis-editing-input-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-ruby-ref.html", + "web-platform-tests/css/css-overflow/text-overflow-string-in-input-notref.html", + "web-platform-tests/css/css-overflow/text-overflow-with-selection-ref.html", "web-platform-tests/css/css-position/absolute-pos-box-inside-fixed-pos-box-with-changing-height-ref.html", "web-platform-tests/css/css-position/backdrop-inherit-rendered-ref.html", "web-platform-tests/css/css-position/block-axis-constraint-changes-for-out-of-flow-box-ref.html", @@ -8406,7 +8493,13 @@ "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-023-ref.html", "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-024-ref.html", "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-025-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-026-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-027-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-028-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-029-ref.html", "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-orthogonal-block-001-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-percentage-slice-multiline-ref.html", + "web-platform-tests/css/css-text-decor/reference/text-decoration-inset-percentage-slice-ref.html", "web-platform-tests/css/css-text-decor/reference/text-decoration-line-010-ref.xht", "web-platform-tests/css/css-text-decor/reference/text-decoration-line-011-ref.xht", "web-platform-tests/css/css-text-decor/reference/text-decoration-line-012-ref.xht", @@ -10034,31 +10127,6 @@ "web-platform-tests/css/css-ui/reference/outline-style-014-ref.html", "web-platform-tests/css/css-ui/reference/outline-with-padding-001-ref.html", "web-platform-tests/css/css-ui/reference/subpixel-outline-width-ref.tentative.html", - "web-platform-tests/css/css-ui/reference/text-overflow-001-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-002-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-005-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-006-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-008-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-012-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-013-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-016-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-021-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-022-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-027-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-028-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-029-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-030-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-change-color-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-indent-001-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-001-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-002-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-003-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-004-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-005-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-006-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-007-ref.html", - "web-platform-tests/css/css-ui/reference/text-overflow-string-008-ref.html", "web-platform-tests/css/css-ui/reference/transparent-accent-color-001-ref.html", "web-platform-tests/css/css-ui/reference/transparent-accent-color-002-ref.html", "web-platform-tests/css/css-ui/resize-change-margin-ref.html", @@ -10098,12 +10166,6 @@ "web-platform-tests/css/css-ui/support/w100.svg", "web-platform-tests/css/css-ui/support/w100_h100.svg", "web-platform-tests/css/css-ui/support/w100_r1-1.svg", - "web-platform-tests/css/css-ui/text-overflow-024-ref.html", - "web-platform-tests/css/css-ui/text-overflow-025-ref.html", - "web-platform-tests/css/css-ui/text-overflow-026-ref.html", - "web-platform-tests/css/css-ui/text-overflow-ref.html", - "web-platform-tests/css/css-ui/text-overflow-ruby-ref.html", - "web-platform-tests/css/css-ui/text-overflow-with-selection-ref.html", "web-platform-tests/css/css-ui/translucent-outline-ref.html", "web-platform-tests/css/css-ui/widget-percentage-height-001-ref.html", "web-platform-tests/css/css-values/attr-in-slotted-ref.html", diff --git a/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires-expected.txt index 575b6d486326..66403af11479 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires-expected.txt @@ -4,9 +4,22 @@ PASS Set cookie with expires value followed by comma via HTTP headers PASS Set cookie with future expiration via HTTP headers PASS Set expired cookie along with valid cookie via HTTP headers PASS Don't set cookie with expires set to the past via HTTP headers +PASS Set cookie with the month before the day of the month in expires via HTTP headers +FAIL Don't set cookie with the month before the day of the month in an expires in the past via HTTP headers assert_equals: The cookie was rejected. expected "" but got "test=7" +FAIL Don't set cookie with no day name and the month before the day of the month in an expires in the past via HTTP headers assert_equals: The cookie was rejected. expected "" but got "test=8" +FAIL Don't set cookie with an expires in the past in Date.prototype.toString() format via HTTP headers assert_equals: The cookie was rejected. expected "" but got "test=9" +PASS Set cookie whose Max-Age overrides an expires in the past via HTTP headers +PASS Set cookie with an asctime format expires, whose time precedes the year via HTTP headers PASS Set cookie with expires value containing a comma via document.cookie PASS Set cookie with expires value followed by comma via document.cookie PASS Set cookie with future expiration via document.cookie PASS Set expired cookie along with valid cookie via document.cookie PASS Don't set cookie with expires set to the past via document.cookie +PASS Set cookie with the month before the day of the month in expires via document.cookie +PASS Don't set cookie with the month before the day of the month in an expires in the past via document.cookie +PASS Don't set cookie with no day name and the month before the day of the month in an expires in the past via document.cookie +PASS Don't set cookie with an expires in the past in Date.prototype.toString() format via document.cookie +PASS Set cookie whose Max-Age overrides an expires in the past via document.cookie +PASS Set cookie with an asctime format expires, whose time precedes the year via document.cookie +PASS Don't set cookie with an expires in the past and a non-ASCII timezone comment via document.cookie diff --git a/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires.html b/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires.html index a6bacfd74e97..28a59482b93c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires.html +++ b/LayoutTests/imported/w3c/web-platform-tests/cookies/attributes/expires.html @@ -40,6 +40,49 @@ expected: "", name: "Don't set cookie with expires set to the past", }, + // RFC 6265 section 5.1.1 finds the day of the month, the month and the year by matching each + // date token independently, so either ordering parses: "10 Apr 1980" and "Apr 10 1980" are + // both valid and denote the same date. Month-first is what JavaScript's + // Date.prototype.toString() produces, and sites pass that to document.cookie in place of + // toUTCString(), so interoperability here is important. + // + // Note that only the past-expiration cases below actually distinguish a conforming + // implementation: if the Expires attribute is ignored, the cookie is stored as a session + // cookie and is therefore still present, so a future expiration looks identical either way. + { + cookie: "test=6; Expires=Fri Jan 01 2038 00:00:00 GMT", + expected: "test=6", + name: "Set cookie with the month before the day of the month in expires", + }, + { + cookie: "test=7; Expires=Thu Apr 10 1980 16:33:12 GMT", + expected: "", + name: "Don't set cookie with the month before the day of the month in an expires in the past", + }, + { + cookie: "test=8; Expires=Apr 10 1980 16:33:12 GMT", + expected: "", + name: "Don't set cookie with no day name and the month before the day of the month in an expires in the past", + }, + { + cookie: "test=9; Expires=Thu Apr 10 1980 16:33:12 GMT-0700 (Pacific Daylight Time)", + expected: "", + name: "Don't set cookie with an expires in the past in Date.prototype.toString() format", + }, + { + cookie: "test=10; Expires=Thu Apr 10 1980 16:33:12 GMT; Max-Age=1000", + expected: "test=10", + name: "Set cookie whose Max-Age overrides an expires in the past", + }, + // The asctime form is also month-first, but it puts the time where Date.prototype.toString() + // puts the year: "Thu Apr 10 16:33:12 1980". It must not be reordered as though the token + // after the day of the month were a year, because "Fri 01 Jan 03:14:07 2038" denotes a date in + // the past, which would drop the cookie instead of storing it. + { + cookie: "test=12; Expires=Fri Jan 01 03:14:07 2038", + expected: "test=12", + name: "Set cookie with an asctime format expires, whose time precedes the year", + }, ]; // These tests evaluate setting cookies with expiration via HTTP headers. @@ -51,6 +94,15 @@ for (const test of expiresTests) { domCookieTest(test.cookie, test.expected, test.name + " via document.cookie"); } + + // A timezone name is localized, so it can be non-ASCII. Date.prototype.toString() only reaches + // a cookie through script, and sending non-ASCII in a response header would exercise header + // encoding at the same time, so this case covers document.cookie only. Same date as test=9, + // written with escapes to keep this file ASCII-only. + domCookieTest( + "test=11; Expires=Thu Apr 10 1980 16:33:12 GMT-0700 (\u0398\u03b5\u03c1\u03b9\u03bd\u03ae \u03ce\u03c1\u03b1 \u0395\u03b9\u03c1\u03b7\u03bd\u03b9\u03ba\u03bf\u03cd)", + "", + "Don't set cookie with an expires in the past and a non-ASCII timezone comment via document.cookie"); - \ No newline at end of file + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html index 09efdaee8415..837c130a8569 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html @@ -2,7 +2,7 @@ - + + + + +
+ +
+ +
+ +
+ +
+ +
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping-expected.txt new file mode 100644 index 000000000000..af79aa29711b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping-expected.txt @@ -0,0 +1,6 @@ + +PASS Default referencing an earlier parameter +PASS Default referencing a later parameter is guaranteed-invalid +PASS Default referencing a later parameter does not see the calling element +PASS Default referencing itself does not see the calling element + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping.html new file mode 100644 index 000000000000..048cfdbdc6cd --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-scoping.html @@ -0,0 +1,78 @@ + +Custom Functions: name scoping in parameter defaults + + + + + + + +
+
+
+
+ + + + + + + + + + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units-expected.txt new file mode 100644 index 000000000000..6d7bb5db743d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units-expected.txt @@ -0,0 +1,13 @@ + +PASS em in a typed parameter +PASS rem in a typed parameter +PASS em within calc() in a typed parameter +PASS em in a typed parameter, untyped return +PASS em in a typed parameter default +PASS em in a typed parameter of a nested function +PASS em in a typed result +PASS em within calc() in a typed result +PASS em in an untyped local substituted into a typed result +PASS em in an untyped parameter +PASS em in an untyped result + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units.html new file mode 100644 index 000000000000..b783527ba19e --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-relative-units.html @@ -0,0 +1,192 @@ + +Custom Functions: font-relative units in parameters, locals and result + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/WEB_FEATURES.yml index c68c9faebee6..282654533f72 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/WEB_FEATURES.yml @@ -1,34 +1,17 @@ -features: -- name: scrollbar-gutter - files: - - scrollbar-gutter-* -- name: overflow-overlay - files: - - overflow-overlay.html -- name: overflow-clip-margin - files: - - overflow-clip-margin-* - - overflow-no-interpolation.html - - paint-containment-svg.html -- name: overflow-clip - files: - - clip-* - - overflow-clip-* - - "!overflow-clip-margin-*" - - dynamic-visible-to-clip-001.html - - rounded-overflow-clip-visible.html -- name: overflow-shorthand - files: - - overflow-* - - "!overflow-auto-scrollbar-gutter-intrinsic-*" - - "!overflow-scroll-*" - - "!overflow-no-interpolation.html" # depends on transition-behavior - - "!overflow-ellipsis-dynamic-001.html" - - "!overflow-clip-*" -- name: column-pseudo - files: - - column-* -- name: text-overflow - files: - - text-overflow-* - - overflow-ellipsis-dynamic-001.html +rules: +- scrollbar-gutter-*: [scrollbar-gutter] +- overflow-overlay.html: [overflow-overlay, overflow-shorthand] +- overflow-clip-margin-*: [overflow-clip-margin] +- overflow-no-interpolation.html: [overflow-clip-margin] # depends on transition-behavior +- paint-containment-svg.html: [overflow-clip-margin] +- clip-*: [overflow-clip] +- overflow-clip-*: [overflow-clip] +- dynamic-visible-to-clip-001.html: [overflow-clip] +- rounded-overflow-clip-visible.html: [overflow-clip] +- overflow-auto-scrollbar-gutter-intrinsic-*: [] +- overflow-scroll-*: [] +- overflow-ellipsis-dynamic-001.html: [text-overflow] +- overflow-*: [overflow-shorthand] +- column-*: [column-pseudo] +- text-overflow-*: [text-overflow] +- text-overflow-string-*: [custom-ellipses, text-overflow] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-expected.txt new file mode 100644 index 000000000000..0fe501cd5f8b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-expected.txt @@ -0,0 +1,4 @@ + +PASS A horizontal scrollbar appears inside the flex container during its layout +PASS An out-of-flow box under the same positioned inline is relaid out after the scrollbar change + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr-expected.txt new file mode 100644 index 000000000000..f1d0a1bc8d9b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr-expected.txt @@ -0,0 +1,4 @@ + +PASS A vertical scrollbar appears inside the flex container during its layout +PASS An out-of-flow box under the same positioned inline is relaid out after the scrollbar change + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr.html new file mode 100644 index 000000000000..3d6a959ed6bd --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant-vertical-lr.html @@ -0,0 +1,64 @@ + + +An absolutely positioned box is still relaid out after a scrollable descendant gains a scrollbar, in vertical-lr + + + +
+ + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant.html new file mode 100644 index 000000000000..ce64c13dd32d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/abspos-relayout-with-scrollable-descendant.html @@ -0,0 +1,68 @@ + + +An absolutely positioned box is still relaid out after a scrollable descendant gains a scrollbar + + + +
+ + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling-expected.html new file mode 100644 index 000000000000..b4c8db95f3e6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling-expected.html @@ -0,0 +1,6 @@ + + +CSS Reftest Reference + +

Test passes if there is a filled green square and no red.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling.html new file mode 100644 index 000000000000..805c01af85b7 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling.html @@ -0,0 +1,59 @@ + + + + Scrolls of `::before` and `::after` pseudo element should persist after a reflow. + + + + + + + + + + +
dummy
+

Test passes if there is a filled green square and no red.

+
+
+ + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/chrome-480554290-crash.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/chrome-480554290-crash.html new file mode 100644 index 000000000000..830ebd5209b2 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/chrome-480554290-crash.html @@ -0,0 +1,30 @@ + + +Chrome crash 480554290 + +
+
+
+
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/clip-002.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/clip-002.html index cec5c7b6e647..cd8b9a3cbeb6 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/clip-002.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/clip-002.html @@ -4,7 +4,6 @@ - +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002-ref.html new file mode 100644 index 000000000000..359a6e7dc919 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002-ref.html @@ -0,0 +1,12 @@ + + +CSS Test Reference: viewport with overflow: clip on the root element + +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002.html new file mode 100644 index 000000000000..18b6205aca29 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/dynamic-visible-to-clip-002.html @@ -0,0 +1,24 @@ + + + +The viewport scrollbar is updated when the root element's overflow is dynamically changed to 'clip' + + + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection-expected.txt new file mode 100644 index 000000000000..8ee065a02d54 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection-expected.txt @@ -0,0 +1,4 @@ + +PASS Near-Z element projected outside border-radius is clipped +FAIL Corner point outside border-radius hits body after perspective assert_not_equals: got disallowed value Element node
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection.html new file mode 100644 index 000000000000..227288e591f5 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-border-radius-and-perspective-projection.html @@ -0,0 +1,63 @@ + +Hit Test border-radius clipping with perspective + + + + + + + + +
+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-stacking-context-parent-border-radius-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-stacking-context-parent-border-radius-expected.txt index 98840b9cb2b3..338f82e89918 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-stacking-context-parent-border-radius-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/hit-test-stacking-context-parent-border-radius-expected.txt @@ -1,18 +1,33 @@ -FAIL Hit testing respects border-radius clipping on elements without creating stacking contexts assert_equals: expected Element node
-
-
- -... but got Element node
-FAIL Hit testing respects border-radius clipping on elements with will-change transform assert_equals: expected Element node
-
-FAIL Hit testing respects border-radius clipping on elements with opacity < 1 assert_equals: expected Element node
-
-FAIL Hit testing respects border-radius clipping on elements with a transform property assert_equals: expected Element node
-
-
-
+
+
+FAIL Hit testing respects border-radius clipping on elements without creating stacking contexts with perspective assert_equals: expected Element node
+
+FAIL Hit testing respects border-radius clipping on elements with will-change transform assert_equals: expected Element node
+
+
+FAIL Hit testing respects border-radius clipping on elements with will-change transform with perspective assert_equals: expected Element node
+
+FAIL Hit testing respects border-radius clipping on elements with opacity < 1 assert_equals: expected Element node
+
+
+FAIL Hit testing respects border-radius clipping on elements with opacity < 1 with perspective assert_equals: expected Element node
+
+FAIL Hit testing respects border-radius clipping on elements with a transform property assert_equals: expected Element node
+
+
+
+
+
+
+
+
+
-
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance-expected.txt index dfda29631576..842aa1fe15d8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance-expected.txt @@ -1,9 +1,9 @@ PASS Property block-ellipsis has initial value no-ellipsis -PASS Property block-ellipsis inherits -PASS Property continue has initial value auto +FAIL Property block-ellipsis inherits assert_equals: expected "ellipsis" but got "no-ellipsis" +FAIL Property continue has initial value normal assert_equals: expected "normal" but got "auto" FAIL Property continue does not inherit assert_equals: expected "collapse" but got "auto" -PASS Property max-lines has initial value none +FAIL Property max-lines has initial value auto assert_equals: expected "auto" but got "none" PASS Property max-lines does not inherit PASS Property overflow-block has initial value visible PASS Property overflow-block does not inherit diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance.html index ced9fa1b6995..e817ffd771eb 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/inheritance.html @@ -15,9 +15,9 @@
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.html similarity index 70% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.html index a00ff6017125..c74f75d9e66c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.html @@ -1,13 +1,13 @@ -CSS Overflow: line-clamp hidden floats should count as ink overflow +CSS Overflow: line-clamp hidden and clipped floats don't count as scrollable overflow - + + +

Test passes if there is a filled green square and no red. + +

+ +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-020-expected.xht b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012-expected.xht similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-020-expected.xht rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012-expected.xht diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012.html new file mode 100644 index 000000000000..524eec50d3cf --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012.html @@ -0,0 +1,58 @@ + + +CSS Overflow: line-clamp clips floats at the block-end only + + + + + + + +

Test passes if there is a filled green square and no red.

+ +
..X
+
+ AAA + X + K + OOO + P +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-034-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-034-ref.html new file mode 100644 index 000000000000..0b7fb78a9535 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-034-ref.html @@ -0,0 +1,11 @@ + + +Test reference + + + +

Test passes if there is no red) diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-035-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-035-ref.html new file mode 100644 index 000000000000..f50980a2cce3 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-035-ref.html @@ -0,0 +1,14 @@ + + +Test reference + + + +

Test passes if there are two lines of text, and the second +line ends with a blue word followed by a closing parenthesis) diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-038-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-038-ref.html new file mode 100644 index 000000000000..5f6dc1ae8990 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-038-ref.html @@ -0,0 +1,10 @@ + + +CSS Overflow: non-empty custom block ellipsis reference + +

First line
PASS CUSTOM
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-039-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-039-ref.html new file mode 100644 index 000000000000..0f44c45f03fe --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-039-ref.html @@ -0,0 +1,27 @@ + + +Test reference + + + +

This test passes if the two boxes below are identical, including having the same height. + +

+ TEST + … +
+
+ TEST + … +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-041-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-041-ref.html new file mode 100644 index 000000000000..2dc26d84ba65 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-041-ref.html @@ -0,0 +1,22 @@ + + +Test reference + + + +

Test passes if there is a “…” below and no red. + +

+ … +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-002-ref.html new file mode 100644 index 000000000000..76231c06e96f --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-002-ref.html @@ -0,0 +1,20 @@ + + +Test reference + + + +

Test passes if there is no red, +and there is an ellipsis character (“…”) on the left side +of the of second line of the text below. + +

+ Story time:
+ "روزی روزگاری… +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-003-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-003-ref.html new file mode 100644 index 000000000000..922d2e9dc505 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-003-ref.html @@ -0,0 +1,28 @@ + + +Test referenec + + + +

Test passes if the text in the blue box matches the one in the orange box. + +

+ Story time:
+ روزی روزگاری… (continued) +
+
+ Story time:
+ روزی روزگاری… (continued) +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-004-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-004-ref.html new file mode 100644 index 000000000000..589212417405 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-004-ref.html @@ -0,0 +1,22 @@ + + +Test reference + + + +

Test passes if the text in the blue box matches the one in the orange box. + +

+ He said "سلام" …آخرہ +
+
+ He said "سلام" …آخرہ +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html index 02ef71d56193..d318a3e662f8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html @@ -2,15 +2,17 @@ CSS Reference
Line 1 Line 2 -Line 3…
-

Following content.

+Line 3
+
Line 4…
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-026-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-026-ref.html index b6e816f997c2..9c0772c2782b 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-026-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-026-ref.html @@ -3,6 +3,7 @@ CSS Reference +
+ +

Line 1

+

Line 2

+

Line 3

+ +

Line 4

+

Line 5

+

Line 6

+ +

Line 7

+

Line 8

+

Line 9

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-041-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-041-ref.html new file mode 100644 index 000000000000..1a42019d7869 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-041-ref.html @@ -0,0 +1,15 @@ + + +CSS Reference + +
Line 1 +Line 2 +Line 3…
+

Following content.

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-043-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-043-ref.html new file mode 100644 index 000000000000..885f931e544b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-043-ref.html @@ -0,0 +1,22 @@ + + + +CSS Overflow: test reference + +
+
+ Line 1
+ Line 2
+ Line 3 +
+ Line B… +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-044-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-044-ref.html new file mode 100644 index 000000000000..746cf6446785 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-044-ref.html @@ -0,0 +1,20 @@ + + + +CSS Overflow: test reference + + +
+

Line 1

+

Line 2

+
Line 3
+

Line 4…

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-045-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-045-ref.html new file mode 100644 index 000000000000..9b4fd5625fa7 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-045-ref.html @@ -0,0 +1,41 @@ + + + +CSS Overflow: test reference + +
+ Line 1
+ Line 2
+ Line 3
+
+ Line A
+ Line B +
+ Line 4
+
+
+
+
Abspos
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-046-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-046-ref.html new file mode 100644 index 000000000000..705f2b0e3e52 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-046-ref.html @@ -0,0 +1,29 @@ + + + +CSS Overflow: test reference + + +
+
+ Line A
+ Line B
+ Line C
+ Line D
+ Line E
+
+ Line 1
+ Line 2
+ Line 3
+ Line 4… +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-047-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-047-ref.html new file mode 100644 index 000000000000..b934b7e6d2d3 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-047-ref.html @@ -0,0 +1,28 @@ + + + +CSS Overflow: test reference + + +
+
+ Line A
+ Line B
+ Line C
+ Line D
+ Line E
+
+ Line 1
+ Line 2… +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html index d20d6c53ddee..e3ebd7baac6d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html @@ -2,22 +2,27 @@ CSS Reference +
Line 1 Line 2 Line 3 Line 4…
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html deleted file mode 100644 index 9288c4e36f92..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html +++ /dev/null @@ -1,28 +0,0 @@ - - -CSS Reference - -
-
Line 1 -Line 2 -Line 3
-
-
Line 4…
-
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html index 6d5390246b4d..56a74d934927 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html @@ -2,25 +2,30 @@ CSS Reference +
Line 1 Line 2 -Line 3 -Line 4…
Line A +Line 3
Line A Line B Line C Line D -Line E
+Line E
+Line 4…
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html index 12b8cdc441a6..d4fbf4b4dbf2 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html @@ -3,13 +3,15 @@ CSS Reference
+
Line 1 Line 2 Line 3 Line 4…
- - +
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/w3c-import.log index 32f977e1da10..2e898babb7de 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-001-ref.html @@ -36,6 +34,14 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-029-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-031-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-032-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-034-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-035-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-038-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-039-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-041-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-002-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-003-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-bidi-004-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-002-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/block-ellipsis-repaint-003-ref.html @@ -53,6 +59,8 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-027-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-028-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-029-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-039-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-041-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-002-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-005-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html @@ -75,6 +83,11 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-039-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-040-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-041-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-043-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-044-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-045-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-046-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-047-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-003-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-auto-with-ruby-005-ref.html @@ -98,9 +111,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-abspos-023-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/line-clamp-with-text-overflow-string-003-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-001-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/w3c-import.log index 3494d9b78b7e..f748a716e3b0 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: box-decoration-break -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/WEB_FEATURES.yml @@ -77,8 +75,39 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-030.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-031-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-031.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032.tentative.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-032.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-033-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-033.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-034-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-034.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-035-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-035.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-036-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-036.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-037-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-037.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-038-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-038.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-039-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-039.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-040-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-040.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-041-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-041.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-001-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-001.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-002-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-002.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-003-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-003.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-004-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-bidi-004.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-crash-001.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-001-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-001.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-002-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-quirk-002.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-repaint-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-repaint-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/block-ellipsis-repaint-002-expected.html @@ -165,6 +194,13 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-037.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-038-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-038.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-039-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-039.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-040-crash.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-041-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-041.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-042-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-042.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-001-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-001.html @@ -247,6 +283,18 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-040.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-041-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-041.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-042-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-042.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-043-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-043.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-044-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-044.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-045-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-045.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-046-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-046.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-047-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-047.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-with-ruby-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-with-ruby-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-auto-with-ruby-002-expected.html @@ -281,10 +329,12 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-balance-011.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-balance-012-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-balance-012.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-bfc-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-bfc-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-bfc.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change.html.rej /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-002-expected.html @@ -331,6 +381,8 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-022.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-023-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-abspos-023.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-block-in-inline-001-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-block-in-inline-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-002-expected.html @@ -365,26 +417,26 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-016.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-017-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-fixed-pos-017.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-001.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-001.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-002.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-002.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-003.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-003.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-008-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-008.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-001-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-001.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-002-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-002.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-003-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-003.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-004.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-005.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-006.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-007.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-010.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-011-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-011.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-floats-012.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-text-overflow-string-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-text-overflow-string-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-with-text-overflow-string-002-expected.html @@ -473,14 +525,10 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-042-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-043-expected.xht /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-043.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-045-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-045.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-046-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-046.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-048-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-048.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-049-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044-expected.html deleted file mode 100644 index 25018d4f59e6..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044-expected.html +++ /dev/null @@ -1,25 +0,0 @@ - - -CSS Test Reference - - -
Line 1 -Line 2 -Line 3 -Line 4 -
Line 5
\ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044.html deleted file mode 100644 index 981e09b466c7..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-044.html +++ /dev/null @@ -1,35 +0,0 @@ - - -CSS Overflow: -webkit-line-clamp creates an IFC - - - - - - -
Line 1 -Line 2 -Line 3 -Line 4 -
Line 5
\ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047-expected.html deleted file mode 100644 index 3f1e31ab2224..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047-expected.html +++ /dev/null @@ -1,25 +0,0 @@ - - -CSS Test Reference - - -
Line 1 -Line 2 -Line 3 -Line 4 -
Line 5…
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047.html deleted file mode 100644 index cb66eb714c51..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-047.html +++ /dev/null @@ -1,38 +0,0 @@ - - -CSS Overflow: -webkit-line-clamp creates an IFC - - - - - - - -
Line 1 -Line 2 -Line 3 -Line 4 -
Line 5
-Line 6 -Line 7
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height-expected.html index c9a9ae5d7ffe..d318a3e662f8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height-expected.html @@ -2,16 +2,17 @@ CSS Reference
Line 1 Line 2 -Line 3 -Line 4…
+Line 3
+
Line 4…
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html index 410fbef9c751..b07d04fbe651 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html @@ -3,19 +3,22 @@ CSS Overflow: -webkit-line-clamp with max-height - - + + @@ -23,6 +26,6 @@ Line 2 Line 3 Line 4 -Line 5 + +Line 7
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant.html index da5056fa95f0..14e5232f06a7 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/max-width-container-with-scrollable-descendant.html @@ -1,7 +1,7 @@ - + + +
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-expected.html index 378da736ecfc..f3aa3676f2e8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-expected.html @@ -13,7 +13,7 @@ height: 100px; will-change: transform; background: black; - box-shadow: 10px 50px 5px red; + box-shadow: 50px 50px 5px green; } .cover { diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-ref.html index 378da736ecfc..f3aa3676f2e8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow-ref.html @@ -13,7 +13,7 @@ height: 100px; will-change: transform; background: black; - box-shadow: 10px 50px 5px red; + box-shadow: 50px 50px 5px green; } .cover { diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow.html index 8ea8e2c3334e..3af937a10e00 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-content-visual-overflow.html @@ -19,19 +19,29 @@ width: 100px; height: 100px; background: black; - box-shadow: 10px 50px 5px red; + box-shadow: 50px 50px 5px green; } .spacer { width: 100px; height: 150px; } + + .fail { + width: 10px; + height: 10px; + background: red; + position: absolute; + z-index: -1; + }
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-hit-testing.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-hit-testing.html index b22497601c2a..b819e3dc00a4 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-hit-testing.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-hit-testing.html @@ -23,7 +23,7 @@ } .child2 { - background-color: red; + background-color: blue; }
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-expected.html index cf6b55a2f91d..3c69cc7c061c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-expected.html @@ -8,8 +8,8 @@ width: 100px; height: 100px; background-color: green; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-ref.html index cf6b55a2f91d..3c69cc7c061c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003-ref.html @@ -8,8 +8,8 @@ width: 100px; height: 100px; background-color: green; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003.html index 52625e90977f..5b74fefd952e 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-003.html @@ -11,8 +11,18 @@ background-color: green; overflow: clip; overflow-clip-margin: 1px; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; + } + .fail { + width: 20px; + height: 20px; + background-color: red; + position: relative; + top: -15px; + left: 85px; + z-index: -1; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-expected.html index cf6b55a2f91d..3c69cc7c061c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-expected.html @@ -8,8 +8,8 @@ width: 100px; height: 100px; background-color: green; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-ref.html index cf6b55a2f91d..3c69cc7c061c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006-ref.html @@ -8,8 +8,8 @@ width: 100px; height: 100px; background-color: green; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006.html index 493bcee29f65..48602c685a6c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-006.html @@ -11,8 +11,18 @@ background-color: green; contain: paint; overflow-clip-margin: 1px; - box-shadow: 20px 20px 5px red; + box-shadow: 20px 20px 5px blue; + } + .fail { + width: 20px; + height: 20px; + background-color: red; + position: relative; + top: -15px; + left: 85px; + z-index: -1; } -

You should see a green box with a red box shadow. +

You should see a green box with a blue box shadow.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013.html new file mode 100644 index 000000000000..7b9e85e3ca64 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-013.html @@ -0,0 +1,31 @@ + + + +overflow-clip-margin: border-box + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014.html new file mode 100644 index 000000000000..fdd5b4f2568a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-014.html @@ -0,0 +1,32 @@ + + + +overflow-clip-margin: content-box + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015.html new file mode 100644 index 000000000000..3c52d3496691 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-015.html @@ -0,0 +1,31 @@ + + + +overflow-clip-margin: keyword + positive length + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016.html new file mode 100644 index 000000000000..2eb0ced43ea2 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-016.html @@ -0,0 +1,33 @@ + + + +overflow-clip-margin: keyword + negative length + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017.html new file mode 100644 index 000000000000..da0623a96c05 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-017.html @@ -0,0 +1,33 @@ + + + +overflow-clip-margin: just a negative length + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018.html new file mode 100644 index 000000000000..fc720d98a058 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-018.html @@ -0,0 +1,32 @@ + + + +overflow-clip-margin: content-box on a scroller + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019.html new file mode 100644 index 000000000000..9219fe38d4a1 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-019.html @@ -0,0 +1,33 @@ + + + +overflow-clip-margin: keyword + negative length on a scroller + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020.html new file mode 100644 index 000000000000..90ce18a5d25d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-020.html @@ -0,0 +1,33 @@ + + + +overflow-clip-margin: just a negative length on a scroller + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021.html new file mode 100644 index 000000000000..5ee29821c6b1 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-021.html @@ -0,0 +1,34 @@ + + + +overflow-clip-margin: border-box is ignored on a scroller + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022.html new file mode 100644 index 000000000000..f55c80e23b64 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-022.html @@ -0,0 +1,34 @@ + + + +overflow-clip-margin: border-box is ignored on a scroller, including the offset + + + + +

Test passes if there is a filled green square.

+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic-expected.html new file mode 100644 index 000000000000..82fcaa3b2aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic-expected.html @@ -0,0 +1,4 @@ + + +

Test passes if there is a filled green square.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic.html new file mode 100644 index 000000000000..be66d7a80c71 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-margin-content-box-dynamic.html @@ -0,0 +1,32 @@ + + + + + + + +

Test passes if there is a filled green square.

+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar-expected.txt new file mode 100644 index 000000000000..cd0b157c9d84 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar-expected.txt @@ -0,0 +1,3 @@ + +PASS overflow: clip on the off-axis does not display a scrollbar. + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar.html new file mode 100644 index 000000000000..b01ff3b919d2 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clip-no-off-axis-scrollbar.html @@ -0,0 +1,42 @@ + + +overflow: clip does not show an off-axis scrollbar + + + + + + +
+
+
+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-expected.html new file mode 100644 index 000000000000..ef8eed504229 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-expected.html @@ -0,0 +1,35 @@ + + +CSS Reference: overflow clipping with transparent borders + +

Test passes if you see two blue squares with green borders, followed by + a green-blue-green striped rectangle where the blue stripe overflows to the right.

+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-ref.html new file mode 100644 index 000000000000..ef8eed504229 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip-ref.html @@ -0,0 +1,35 @@ + + +CSS Reference: overflow clipping with transparent borders + +

Test passes if you see two blue squares with green borders, followed by + a green-blue-green striped rectangle where the blue stripe overflows to the right.

+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip.html new file mode 100644 index 000000000000..fcda5ab7a96e --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-clipped-transparent-border-clip.html @@ -0,0 +1,56 @@ + + +CSS Test: overflow clipping preserves background visible through transparent borders + + + + + +

Test passes if you see two blue squares with green borders, followed by + a green-blue-green striped rectangle where the blue stripe overflows to the right.

+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-hidden-resize-with-stacking-context-child.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-hidden-resize-with-stacking-context-child.html index 8569ac153329..c76cce507aa5 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-hidden-resize-with-stacking-context-child.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-hidden-resize-with-stacking-context-child.html @@ -22,6 +22,14 @@ height: 20px; background: green; } +.fail { + width: 20px; + height: 20px; + background: red; + position: relative; + top: -60px; + left: 40px; +}

Test passes if there is a filled green square.

@@ -33,6 +41,7 @@
+
+ + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-video-hidden.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-video-hidden.html new file mode 100644 index 000000000000..aaa866ca72d9 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/overflow-video-hidden.html @@ -0,0 +1,29 @@ + + + +Verifies overflow: hidden applies to video elements + + + + + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/WEB_FEATURES.yml index 7db666f28122..773f30e499bf 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/WEB_FEATURES.yml @@ -1,20 +1,9 @@ -features: -- name: overflow-clip-margin - files: - - overflow-clip-margin* -- name: scroll-markers - files: - - scroll-markers* -- name: scroll-buttons - files: - - scroll-button* -- name: scrollbar-gutter - files: - - scrollbar-gutter-* -- name: line-clamp - files: - - line-clamp-* - - webkit-line-clamp-* -- name: text-overflow - files: - - text-overflow-* +rules: +- overflow-clip-margin*: [overflow-clip-margin] +- scroll-markers*: [scroll-markers] +- scroll-button*: [scroll-buttons] +- scroll-target-group*: [scroll-target-group] +- scrollbar-gutter-*: [scrollbar-gutter] +- line-clamp-*: [line-clamp] +- webkit-line-clamp-*: [line-clamp] +- text-overflow-*: [text-overflow] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid-expected.txt index b8b1e2aa7e69..a9047ff04b41 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid-expected.txt @@ -1,9 +1,12 @@ PASS e.style['block-ellipsis'] = "hidden" should not set the property value PASS e.style['block-ellipsis'] = "none" should not set the property value +FAIL e.style['block-ellipsis'] = "auto" should not set the property value assert_equals: expected "" but got "auto" PASS e.style['block-ellipsis'] = "none auto" should not set the property value PASS e.style['block-ellipsis'] = "no-ellipsis auto" should not set the property value +PASS e.style['block-ellipsis'] = "ellipsis auto" should not set the property value PASS e.style['block-ellipsis'] = "auto \"string\"" should not set the property value +PASS e.style['block-ellipsis'] = "ellipsis \"string\"" should not set the property value PASS e.style['block-ellipsis'] = "\"string\" none" should not set the property value PASS e.style['block-ellipsis'] = "\"string\" no-ellipsis" should not set the property value PASS e.style['block-ellipsis'] = "\"first\" \"second\"" should not set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid.html index e9fcca411d90..486ddae01299 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-invalid.html @@ -4,7 +4,7 @@ CSS Overflow: parsing block-ellipsis with invalid values - + @@ -13,10 +13,13 @@ @@ -12,7 +12,7 @@ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid-expected.txt index ebbb5240a0d1..0a4ce5c68f5a 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid-expected.txt @@ -1,6 +1,11 @@ PASS e.style['continue'] = "none" should not set the property value +FAIL e.style['continue'] = "auto" should not set the property value assert_equals: expected "" but got "auto" PASS e.style['continue'] = "auto discard" should not set the property value PASS e.style['continue'] = "auto collapse" should not set the property value PASS e.style['continue'] = "auto -webkit-legacy" should not set the property value +PASS e.style['continue'] = "normal discard" should not set the property value +PASS e.style['continue'] = "normal collapse" should not set the property value +PASS e.style['continue'] = "normal -webkit-legacy" should not set the property value +PASS e.style['continue'] = "collapse -webkit-legacy" should not set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid.html index df09e0912beb..6c14c7751bb2 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid.html @@ -4,7 +4,7 @@ CSS Overflow: parsing continue with invalid values - + @@ -12,10 +12,15 @@ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid-expected.txt index ba991634ee46..c987fbffd116 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid-expected.txt @@ -1,5 +1,5 @@ -PASS e.style['continue'] = "auto" should set the property value +FAIL e.style['continue'] = "normal" should set the property value assert_not_equals: property should be set got disallowed value "" PASS e.style['continue'] = "discard" should set the property value FAIL e.style['continue'] = "collapse" should set the property value assert_not_equals: property should be set got disallowed value "" FAIL e.style['continue'] = "-webkit-legacy" should set the property value assert_not_equals: property should be set got disallowed value "" diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid.html index 9d9f71e79ccf..571678e81739 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid.html @@ -4,14 +4,14 @@ CSS Overflow: parsing continue with valid values - + + + +
+
+
+
+
+
+
+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid-expected.txt index 39fccc90cde1..969bd90e82e5 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid-expected.txt @@ -4,6 +4,7 @@ PASS e.style['line-clamp'] = "-5" should not set the property value PASS e.style['line-clamp'] = "none 2" should not set the property value PASS e.style['line-clamp'] = "none no-ellipsis" should not set the property value PASS e.style['line-clamp'] = "3 none" should not set the property value +PASS e.style['line-clamp'] = "3 ellipsis auto" should not set the property value PASS e.style['line-clamp'] = "-webkit-legacy" should not set the property value PASS e.style['line-clamp'] = "0 -webkit-legacy" should not set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid.html index 36665f7d9bb6..6d3155714934 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid.html @@ -18,6 +18,7 @@ test_invalid_value("line-clamp", 'none 2'); test_invalid_value("line-clamp", 'none no-ellipsis'); test_invalid_value("line-clamp", '3 none'); +test_invalid_value("line-clamp", '3 ellipsis auto'); test_invalid_value("line-clamp", '-webkit-legacy'); test_invalid_value("line-clamp", '0 -webkit-legacy'); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid-expected.txt index 088a30672e3d..3c45aa81db79 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid-expected.txt @@ -3,12 +3,15 @@ PASS e.style['line-clamp'] = "none" should set the property value PASS e.style['line-clamp'] = "1" should set the property value PASS e.style['line-clamp'] = "6" should set the property value FAIL e.style['line-clamp'] = "auto" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['line-clamp'] = "ellipsis" should set the property value assert_not_equals: property should be set got disallowed value "" FAIL e.style['line-clamp'] = "\" etc., etc. \"" should set the property value assert_not_equals: property should be set got disallowed value "" FAIL e.style['line-clamp'] = "7 no-ellipsis" should set the property value assert_not_equals: property should be set got disallowed value "" -PASS e.style['line-clamp'] = "8 auto" should set the property value +FAIL e.style['line-clamp'] = "8 auto" should set the property value assert_equals: serialization should be canonical expected "8 auto" but got "8" +FAIL e.style['line-clamp'] = "8 ellipsis" should set the property value assert_not_equals: property should be set got disallowed value "" PASS e.style['line-clamp'] = "9 \" etc., etc. \"" should set the property value FAIL e.style['line-clamp'] = "no-ellipsis 10" should set the property value assert_not_equals: property should be set got disallowed value "" -PASS e.style['line-clamp'] = "auto 11" should set the property value +FAIL e.style['line-clamp'] = "auto 11" should set the property value assert_equals: serialization should be canonical expected "11 auto" but got "11" +FAIL e.style['line-clamp'] = "ellipsis 11" should set the property value assert_not_equals: property should be set got disallowed value "" PASS e.style['line-clamp'] = "\" etc., etc. \" 12" should set the property value FAIL e.style['line-clamp'] = "1 -webkit-legacy" should set the property value assert_not_equals: property should be set got disallowed value "" FAIL e.style['line-clamp'] = "auto -webkit-legacy" should set the property value assert_not_equals: property should be set got disallowed value "" diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid.html index 870049809b2d..e8d76921e795 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid.html @@ -15,22 +15,26 @@ test_valid_value("line-clamp", '1'); test_valid_value("line-clamp", '6'); - test_valid_value("line-clamp", 'auto'); -test_valid_value("line-clamp", '" etc., etc. "'); + +test_valid_value("line-clamp", 'ellipsis', 'auto'); +test_valid_value("line-clamp", '" etc., etc. "', 'auto " etc., etc. "'); test_valid_value("line-clamp", '7 no-ellipsis'); -test_valid_value("line-clamp", '8 auto', '8'); +test_valid_value("line-clamp", '8 auto'); +test_valid_value("line-clamp", '8 ellipsis', '8'); test_valid_value("line-clamp", '9 " etc., etc. "'); test_valid_value("line-clamp", 'no-ellipsis 10', '10 no-ellipsis'); -test_valid_value("line-clamp", 'auto 11', '11'); +test_valid_value("line-clamp", 'auto 11', '11 auto'); +test_valid_value("line-clamp", 'ellipsis 11', '11'); test_valid_value("line-clamp", '" etc., etc. " 12', '12 " etc., etc. "'); test_valid_value("line-clamp", '1 -webkit-legacy'); test_valid_value("line-clamp", 'auto -webkit-legacy'); -test_valid_value("line-clamp", 'no-ellipsis -webkit-legacy'); -test_valid_value("line-clamp", '3 auto -webkit-legacy', '3 -webkit-legacy'); +test_valid_value("line-clamp", 'no-ellipsis -webkit-legacy', + 'auto no-ellipsis -webkit-legacy'); +test_valid_value("line-clamp", '3 auto -webkit-legacy'); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid-expected.txt index e677f48aa9aa..a0590005992d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid-expected.txt @@ -1,8 +1,9 @@ -PASS e.style['max-lines'] = "auto" should not set the property value +FAIL e.style['max-lines'] = "none" should not set the property value assert_equals: expected "" but got "none" PASS e.style['max-lines'] = "0" should not set the property value PASS e.style['max-lines'] = "-5" should not set the property value PASS e.style['max-lines'] = "none none" should not set the property value +PASS e.style['max-lines'] = "auto auto" should not set the property value PASS e.style['max-lines'] = "1 none" should not set the property value PASS e.style['max-lines'] = "none 2" should not set the property value PASS e.style['max-lines'] = "3 4" should not set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid.html index 8b6da0dcb896..5fa973650be6 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid.html @@ -12,11 +12,12 @@ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin-expected.txt index e94cb0959024..5054b44d3ab3 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin-expected.txt @@ -23,4 +23,5 @@ PASS e.style['overflow-clip-margin'] = "border-box calc(0.5em - 100px)" should s PASS e.style['overflow-clip-margin'] = "border-box calc(0.5em - 100%)" should not set the property value PASS e.style['overflow-clip-margin'] = "margin-box" should not set the property value PASS e.style['overflow-clip-margin'] = "inset(10px)" should not set the property value +PASS e.style['overflow-clip-margin'] = "50px 50px" should not set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin.html index e1efee596ec0..2a1b988c5724 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-clip-margin.html @@ -40,6 +40,7 @@ test_invalid_value("overflow-clip-margin", 'margin-box'); test_invalid_value("overflow-clip-margin", 'inset(10px)'); +test_invalid_value("overflow-clip-margin", '50px 50px'); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed-expected.txt index fa7112933026..1dd040b531b4 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed-expected.txt @@ -5,17 +5,17 @@ PASS Property overflow value 'clip' PASS Property overflow value 'scroll' PASS Property overflow value 'auto' PASS Property overflow value 'auto auto' -PASS Property overflow value 'auto clip' +FAIL Property overflow value 'auto clip' assert_equals: expected "auto clip" but got "auto hidden" PASS Property overflow value 'auto visible' -PASS Property overflow value 'clip auto' +FAIL Property overflow value 'clip auto' assert_equals: expected "clip auto" but got "hidden auto" PASS Property overflow value 'clip clip' -PASS Property overflow value 'clip hidden' -PASS Property overflow value 'clip scroll' +FAIL Property overflow value 'clip hidden' assert_equals: expected "clip hidden" but got "hidden" +FAIL Property overflow value 'clip scroll' assert_equals: expected "clip scroll" but got "hidden scroll" PASS Property overflow value 'clip visible' -PASS Property overflow value 'hidden clip' +FAIL Property overflow value 'hidden clip' assert_equals: expected "hidden clip" but got "hidden" PASS Property overflow value 'hidden visible' PASS Property overflow value 'scroll auto' -PASS Property overflow value 'scroll clip' +FAIL Property overflow value 'scroll clip' assert_equals: expected "scroll clip" but got "scroll hidden" PASS Property overflow value 'scroll visible' PASS Property overflow value 'visible auto' PASS Property overflow value 'visible hidden' diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed.html index 563d1b31d259..a7d6e2fa3133 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed.html @@ -4,7 +4,7 @@ CSS Overflow: getComputedStyle().overflow - + @@ -19,17 +19,17 @@ test_computed_value("overflow", 'auto'); test_computed_value("overflow", 'auto auto', 'auto'); -test_computed_value("overflow", 'auto clip', 'auto hidden'); +test_computed_value("overflow", 'auto clip'); test_computed_value("overflow", 'auto visible', 'auto'); -test_computed_value("overflow", 'clip auto', 'hidden auto'); +test_computed_value("overflow", 'clip auto'); test_computed_value("overflow", 'clip clip', 'clip'); -test_computed_value("overflow", 'clip hidden', 'hidden'); -test_computed_value("overflow", 'clip scroll', 'hidden scroll') -test_computed_value("overflow", 'clip visible', 'clip visible') -test_computed_value("overflow", 'hidden clip', 'hidden'); +test_computed_value("overflow", 'clip hidden'); +test_computed_value("overflow", 'clip scroll'); +test_computed_value("overflow", 'clip visible', 'clip visible'); +test_computed_value("overflow", 'hidden clip'); test_computed_value("overflow", 'hidden visible', 'hidden auto'); test_computed_value("overflow", 'scroll auto'); -test_computed_value("overflow", 'scroll clip', 'scroll hidden'); +test_computed_value("overflow", 'scroll clip'); test_computed_value("overflow", 'scroll visible', 'scroll auto'); test_computed_value("overflow", 'visible auto', 'auto'); test_computed_value("overflow", 'visible hidden', 'auto hidden'); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed-expected.txt new file mode 100644 index 000000000000..dccad9439cd0 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed-expected.txt @@ -0,0 +1,10 @@ + +FAIL Property scroll-axis-lock value 'initial' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL Property scroll-axis-lock value 'inherit' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL Property scroll-axis-lock value 'unset' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL Property scroll-axis-lock value 'revert' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL Property scroll-axis-lock value 'auto' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL Property scroll-axis-lock value 'none' assert_true: scroll-axis-lock doesn't seem to be supported in the computed style expected true got false +FAIL The scroll-axis-lock property shows up in CSSStyleDeclaration enumeration assert_not_equals: got disallowed value -1 +FAIL The scroll-axis-lock property shows up in CSSStyleDeclaration.cssText assert_not_equals: got disallowed value -1 + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed.html new file mode 100644 index 000000000000..6b14cd9165d0 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed.html @@ -0,0 +1,27 @@ + + +CSS Overflow: parsing scroll-axis-lock property computed values + + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid-expected.txt new file mode 100644 index 000000000000..45a60854380f --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid-expected.txt @@ -0,0 +1,9 @@ + +PASS e.style['scroll-axis-lock'] = "10" should not set the property value +PASS e.style['scroll-axis-lock'] = "true" should not set the property value +PASS e.style['scroll-axis-lock'] = "default" should not set the property value +PASS e.style['scroll-axis-lock'] = "all" should not set the property value +PASS e.style['scroll-axis-lock'] = "auto, none" should not set the property value +PASS e.style['scroll-axis-lock'] = "always" should not set the property value +PASS e.style['scroll-axis-lock'] = "both" should not set the property value + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid.html new file mode 100644 index 000000000000..00e5b920a8b4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid.html @@ -0,0 +1,17 @@ + + +CSS Overflow: parsing scroll-axis-lock property invalid values + + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid-expected.txt new file mode 100644 index 000000000000..4a367297066c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid-expected.txt @@ -0,0 +1,8 @@ + +FAIL e.style['scroll-axis-lock'] = "initial" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['scroll-axis-lock'] = "inherit" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['scroll-axis-lock'] = "unset" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['scroll-axis-lock'] = "revert" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['scroll-axis-lock'] = "auto" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['scroll-axis-lock'] = "none" should set the property value assert_not_equals: property should be set got disallowed value "" + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid.html new file mode 100644 index 000000000000..0a67bba52b2b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid.html @@ -0,0 +1,17 @@ + + +CSS Overflow: parsing scroll-axis-lock property valid values + + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-markers-computed.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-markers-computed.html index 882ed83fe723..b9a68c20f094 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-markers-computed.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-markers-computed.html @@ -18,8 +18,8 @@ test_computed_value('scroll-marker-group', 'revert', 'none'); test_computed_value('scroll-marker-group', 'none'); - test_computed_value('scroll-marker-group', 'before'); - test_computed_value('scroll-marker-group', 'after'); + test_computed_value('scroll-marker-group', 'before', 'before links'); + test_computed_value('scroll-marker-group', 'after', 'after links'); test(() => { let style = getComputedStyle(document.getElementById('target')); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-computed-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-computed-expected.txt index e20a35252395..4194f4bc6160 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-computed-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-computed-expected.txt @@ -1,7 +1,7 @@ PASS Property text-overflow value 'clip' PASS Property text-overflow value 'ellipsis' -FAIL Property text-overflow value '""' assert_true: '""' is a supported value for text-overflow. expected true got false -FAIL Property text-overflow value '"-"' assert_true: '"-"' is a supported value for text-overflow. expected true got false -FAIL Property text-overflow value '"marker string"' assert_true: '"marker string"' is a supported value for text-overflow. expected true got false +PASS Property text-overflow value '""' +PASS Property text-overflow value '"-"' +PASS Property text-overflow value '"marker string"' diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-valid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-valid-expected.txt index 6da8efaf3cc8..7d238f2b3c1b 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-valid-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/text-overflow-valid-expected.txt @@ -1,7 +1,7 @@ PASS e.style['text-overflow'] = "clip" should set the property value PASS e.style['text-overflow'] = "ellipsis" should set the property value -FAIL e.style['text-overflow'] = "\"\"" should set the property value assert_not_equals: property should be set got disallowed value "" -FAIL e.style['text-overflow'] = "\"-\"" should set the property value assert_not_equals: property should be set got disallowed value "" -FAIL e.style['text-overflow'] = "\"marker string\"" should set the property value assert_not_equals: property should be set got disallowed value "" +PASS e.style['text-overflow'] = "\"\"" should set the property value +PASS e.style['text-overflow'] = "\"-\"" should set the property value +PASS e.style['text-overflow'] = "\"marker string\"" should set the property value diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/w3c-import.log index 60907de1ad53..1d6008ff03a8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/WEB_FEATURES.yml @@ -19,6 +17,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/block-ellipsis-valid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-invalid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/continue-valid.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/getComputedStyle-scroll-button.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-invalid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/line-clamp-valid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/max-lines-invalid.html @@ -28,6 +27,9 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-computed.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-invalid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/overflow-valid.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-computed.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-invalid.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-axis-lock-valid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-buttons-invalid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-buttons-valid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/parsing/scroll-markers-computed.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/before-after-pseudo-element-scrolling-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/before-after-pseudo-element-scrolling-ref.html new file mode 100644 index 000000000000..b4c8db95f3e6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/before-after-pseudo-element-scrolling-ref.html @@ -0,0 +1,6 @@ + + +CSS Reftest Reference + +

Test passes if there is a filled green square and no red.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-001-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-001-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-001-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-002-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-002-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-002-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-005-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-005-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-005-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-005-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-006-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-006-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-006-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-006-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-008-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-008-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-008-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-008-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-012-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-012-ref.html similarity index 95% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-012-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-012-ref.html index 700f9c896fe9..707f93d79c49 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-012-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-012-ref.html @@ -9,7 +9,7 @@ color: green; } span { - color: white; + color: white; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-013-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-013-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-013-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-013-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-016-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-016-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-016-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-016-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-021-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-021-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-021-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-021-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-022-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-022-ref.html similarity index 93% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-022-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-022-ref.html index db7d08f45045..31501b868471 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-022-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-022-ref.html @@ -9,7 +9,7 @@ color: green; } span { - color: transparent; + color: transparent; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-027-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-027-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-027-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-027-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-028-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-028-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-028-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-028-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-029-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-029-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-029-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-029-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-030-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-030-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-030-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-030-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-change-color-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-change-color-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-change-color-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-change-color-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-editable-div-with-caret-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-editable-div-with-caret-ref.html new file mode 100644 index 000000000000..97e1ffdca126 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-editable-div-with-caret-ref.html @@ -0,0 +1,29 @@ + + +Reference for text-overflow ellipsis in editable div with caret selection + + +
This is a very long text that should be clipped
+ + \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-indent-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-indent-001-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-indent-001-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-indent-001-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-multiline-001-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-multiline-001-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-textarea-with-caret-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-textarea-with-caret-ref.html new file mode 100644 index 000000000000..77bfc030f70f --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-textarea-with-caret-ref.html @@ -0,0 +1,25 @@ + + +Reference for text-overflow ellipsis in textarea with caret selection + + + \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-001-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-001-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-001-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-002-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-002-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-002-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-003-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-003-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-003-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-003-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-004-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-004-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-004-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-004-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-005-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-005-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-005-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-005-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-006-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-006-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-006-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-006-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-007-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-007-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-007-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-007-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-008-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-008-ref.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-008-ref.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-008-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-009-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-009-ref.html new file mode 100644 index 000000000000..3a3b90047ef4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-009-ref.html @@ -0,0 +1,25 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an 안녕 안녕 after a black rectangle below.

+
+ Test안녕 안녕 +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-010-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-010-ref.html new file mode 100644 index 000000000000..2a76f91ed132 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-010-ref.html @@ -0,0 +1,25 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an 안녕 你好 after a black rectangle below.

+
+ Test안녕 你好 +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-011-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-011-ref.html new file mode 100644 index 000000000000..0e89803a16ea --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-011-ref.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an Hi ワールド after a black rectangle below.

+
+ TestHi ワールド +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-012-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-012-ref.html new file mode 100644 index 000000000000..6134b3efd9f6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-012-ref.html @@ -0,0 +1,29 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an 안녕 🟢 after a black rectangle below.

+
+ Test안녕 🟢 +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-013-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-013-ref.html new file mode 100644 index 000000000000..cc57fa1e6441 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-013-ref.html @@ -0,0 +1,25 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an 你好 🟢 after a black rectangle below.

+
+ Test你好 🟢 +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-014-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-014-ref.html new file mode 100644 index 000000000000..2d24573aaa9e --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-014-ref.html @@ -0,0 +1,25 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an שלום 你好 after a black rectangle below.

+
+ Testשלום 你好 +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-015-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-015-ref.html new file mode 100644 index 000000000000..3a70eecf878b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-015-ref.html @@ -0,0 +1,29 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an יְוֹם 낮 after a black rectangle below.

+
+ Testיְוֹם 낮 +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-016-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-016-ref.html new file mode 100644 index 000000000000..1076f4939711 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-016-ref.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an Hi Hi after a black rectangle below.

+
+ TestHi Hi +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-024-ref.tentative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-024-ref.tentative.html new file mode 100644 index 000000000000..97a5a87438dd --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-024-ref.tentative.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an こんにちは after a black rectangle below.

+
+ Testこんにちは +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-025-ref.tentative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-025-ref.tentative.html new file mode 100644 index 000000000000..ae378c472c19 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-025-ref.tentative.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an 你好你好 after a black rectangle below.

+
+ Test你好你好 +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-026-ref.tentative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-026-ref.tentative.html new file mode 100644 index 000000000000..594a188b001c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-026-ref.tentative.html @@ -0,0 +1,21 @@ + + +CSS Basic User Interface Reference File + + + + +

Test passes if there is an FULL after a black rectangle below.

+
+ TestFULL +
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/w3c-import.log index f61c0946ce17..8b242c970423 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/w3c-import.log @@ -10,10 +10,9 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/before-after-pseudo-element-scrolling-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/input-scrollable-region-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/overflow-body-no-propagation-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/overflow-body-propagation-ref.html @@ -21,12 +20,50 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/overflow-inline-block-with-opacity-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/overflow-recalc-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/ref-if-there-is-no-red.xht +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-001-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-002-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-005-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-006-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-008-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-012-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-013-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-016-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-021-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-022-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-027-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-028-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-029-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-030-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-change-color-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-002-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-editable-div-with-caret-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-indent-001-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-multiline-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-rtl-001-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-textarea-with-caret-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-vertical-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-ellipsis-vertical-rtl-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-scroll-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-scroll-rtl-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-scroll-vertical-lr-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-scroll-vertical-lr-rtl-001-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-001-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-002-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-003-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-004-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-005-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-006-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-007-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-008-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-009-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-010-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-011-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-012-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-013-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-014-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-015-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-016-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-024-ref.tentative.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-025-ref.tentative.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/reference/text-overflow-string-026-ref.tentative.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock-expected.txt new file mode 100644 index 000000000000..224d30a3ae00 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock-expected.txt @@ -0,0 +1,6 @@ + +Harness Error (TIMEOUT), message = null + +TIMEOUT scroll-axis-lock: none allows free diagonal touch scroll even with steep angle (no railing) Test timed out +NOTRUN scroll-axis-lock: none allows free diagonal wheel scroll even with steep angle (no railing) + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock.html new file mode 100644 index 000000000000..583ed053f332 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-axis-lock.html @@ -0,0 +1,125 @@ + +CSS Scroll Snap: scroll-axis-lock + + + + + + + + + +
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none-expected.txt new file mode 100644 index 000000000000..cff8a4a2d85d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none-expected.txt @@ -0,0 +1,4 @@ +Item + +PASS No crash when scroll-marker-group is display: none during focus navigation + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none.html new file mode 100644 index 000000000000..f59139223faa --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-display-none.html @@ -0,0 +1,47 @@ + +CSS Overflow: scroll markers crash with display:none + + + + + + +
+
Item
+
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-expected.txt new file mode 100644 index 000000000000..8d7713226b0d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-expected.txt @@ -0,0 +1,3 @@ + +FAIL CSS Overflow Test: ::scroll-marker-group supports hover assert_equals: ::scroll-marker-group is unhovered expected "rgb(255, 0, 0)" but got "" + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker-expected.txt new file mode 100644 index 000000000000..96e33d3a6cb9 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker-expected.txt @@ -0,0 +1,3 @@ + +FAIL CSS Overflow Test: ::scroll-marker-group matches hover when inner ::scroll-marker is hovered assert_equals: ::scroll-marker-group is unhovered initially expected "rgb(255, 0, 0)" but got "" + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker.html new file mode 100644 index 000000000000..7ad3ee10f315 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover-from-marker.html @@ -0,0 +1,64 @@ + + +CSS Overflow Test: ::scroll-marker-group matches hover when inner ::scroll-marker is hovered + + + + + + + +
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover.html new file mode 100644 index 000000000000..9b8097105bbc --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-marker-group-hover.html @@ -0,0 +1,42 @@ + + +CSS Overflow Test: ::scroll-marker-group supports hover + + + + + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yaml b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yaml deleted file mode 100644 index b3862f22ed98..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yaml +++ /dev/null @@ -1,18 +0,0 @@ -features: -- name: scroll-markers - files: - - column-scroll-marker* - - html-scroll-marker* - - inline-with-scroll-marker* - - nested-scroll-markers* - - root-scroll-marker* - - scroll-marker* - - target-current-scroll-marker-update.html - - targeted-column-scroll-marker* - - targeted-scroll-marker* - - chrome-421199213-crash.html - - targeted-column-scroll-marker-selection-* -- name: scroll-buttons - files: - - root-scroll-button* - - scroll-button* diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yml new file mode 100644 index 000000000000..70efb93af80b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yml @@ -0,0 +1,15 @@ +rules: +- column-scroll-marker*: [scroll-markers] +- html-scroll-marker*: [scroll-marker-targets] +- inline-with-scroll-marker*: [scroll-markers] +- nested-scroll-markers*: [scroll-markers] +- root-scroll-marker*: [scroll-markers] +- scroll-marker-target-before-after.html: [scroll-marker-targets] +- scroll-marker*: [scroll-markers] +- target-current-scroll-marker-update.html: [scroll-markers] +- targeted-column-scroll-marker*: [scroll-markers, scroll-markers] +- targeted-scroll-marker*: [scroll-markers] +- chrome-421199213-crash.html: [scroll-markers] +- root-scroll-button*: [scroll-buttons] +- scroll-button*: [scroll-buttons] +- scroll-target-group*: [scroll-target-group] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/resources/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/resources/w3c-import.log index dea262857ba6..3a0bc3ad17e9 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/resources/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/resources/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/resources/root-scroll-marker-activation-iframe.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-display-none.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-display-none.html index 8b3068be6dad..35e87c5556c1 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-display-none.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-display-none.html @@ -51,4 +51,22 @@ .send(); assert_true(true); }); + + promise_test(async t => { + // Restore the scroller visibility hidden by the previous test. + scroller.className = ""; + document.documentElement.offsetTop; + + // Removing the scroller inside a bubble-phase listener. So that by the + // time a handler is called the pseudo-element is already disconnected. + scroller.addEventListener('click', () => scroller.remove(), { once: true }); + + await new test_driver.Actions() + .pointerMove(15, 15) + .pointerDown() + .pointerUp() + .send(); + + assert_true(true, "no crash when container removed during event bubbling"); + }, "scroll-button click removing container during bubbling does not crash"); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-expected.html new file mode 100644 index 000000000000..65707c53527c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-expected.html @@ -0,0 +1,15 @@ + +CSS Overflow Test: ::scroll-button positioning works after position type transitions + +

You should see a green square below.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-ref.html new file mode 100644 index 000000000000..65707c53527c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-ref.html @@ -0,0 +1,15 @@ + +CSS Overflow Test: ::scroll-button positioning works after position type transitions + +

You should see a green square below.

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position.html new file mode 100644 index 000000000000..c9ebb585e3fc --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position.html @@ -0,0 +1,34 @@ + +CSS Overflow Test: ::scroll-button positioning works after position type transitions + + + +

You should see a green square below.

+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-activation-retains-focus.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-activation-retains-focus.html index cf38ed354c73..054a87011993 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-activation-retains-focus.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-activation-retains-focus.html @@ -1,6 +1,6 @@ -CSS Test: ::scroll-marker retains focus on ::scroll-marker +CSS Test: ::scroll-marker activation focus behavior in links and tabs modes @@ -51,12 +51,25 @@
\ No newline at end of file + assert_equals(getComputedStyle(target, "::scroll-marker").backgroundColor, "rgb(0, 0, 255)", "::scroll-marker activation retains focus in tabs mode"); + }, "::scroll-marker activation focus behavior in links and tabs modes"); + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-double-activation.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-double-activation.html index ee621980c286..d6d14e4d90f8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-double-activation.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-double-activation.html @@ -1,6 +1,6 @@ -CSS Values Test: ::scroll-marker double activation scrolls into view twice +CSS Values Test: ::scroll-marker double activation scrolls into view twice in links and tabs modes @@ -51,13 +51,36 @@
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-focus-within.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-focus-within.html index 7a094b2bfd45..4cd3945bd21a 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-focus-within.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-focus-within.html @@ -1,6 +1,6 @@ -CSS Overflow Test: focused ::scroll-marker sets :focus-within on its ::scroll-marker-group, scroller and all the ancestors +CSS Overflow Test: focused ::scroll-marker sets :focus-within on its ::scroll-marker-group, scroller and all the ancestors in links and tabs modes @@ -65,24 +65,31 @@
\ No newline at end of file + assert_equals(getComputedStyle(scroller, "::scroll-marker-group").backgroundColor, "rgb(0, 128, 0)", "focused ::scroll-marker sets :focus-within on its ::scroll-marker-group in tabs mode"); + assert_equals(getComputedStyle(scroller).backgroundColor, "rgb(0, 128, 0)", "focused ::scroll-marker sets :focus-within on its scroller in tabs mode"); + assert_equals(getComputedStyle(target, "::scroll-marker").backgroundColor, "rgb(0, 128, 0)", "focused ::scroll-marker sets :focus-within on itself in tabs mode"); + assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)", "focused ::scroll-marker doesn't set :focus-within on its originating element in tabs mode"); + }, "::scroll-marker sets :focus-within on its ancestors in tabs mode, but not in links mode"); + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-003.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-003.html new file mode 100644 index 000000000000..362f715f6a45 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-003.html @@ -0,0 +1,49 @@ + +CSS Overflow Test: ::scroll-marker-group inertness applied to display:contents ::scroll-marker + + + + + + + + + +
+
+
+
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-navigation-cycles.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-navigation-cycles.html index d41b720ed925..5dfe09053c90 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-navigation-cycles.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-navigation-cycles.html @@ -14,54 +14,206 @@ } #scroller { + background: white; overflow: auto; - width: 100px; - height: 100px; - scroll-marker-group: before; + width: 600px; + height: 300px; + /* use tabs mode so activated markers receive focus and can handle + arrow-key events directly */ + scroll-marker-group: before tabs; white-space: nowrap; } #scroller::scroll-marker-group { display: flex; - height: 10px; - width: 30px; + height: 20px; + width: 300px; } #scroller div { background: blue; display: inline-block; - height: 100px; - width: 100px; + height: 280px; + width: 600px; } #scroller div::scroll-marker { content: ""; background: blue; - width: 10px; - height: 10px; + display: inline-block; + width: 30px; + height: 20px; + opacity: 1; } #scroller div::scroll-marker:target-current { background: green; } + + #scroller div::scroll-marker:focus { + opacity: 0.5; + }
-
+
\ No newline at end of file + await waitForRenderingUpdate(); + } + + async function resetScrollerStyles() { + scroller.style.direction = 'ltr'; + scroller.style.writingMode = 'horizontal-tb'; + scroller.scrollTo({ left: 0, top: 0, behavior: 'instant' }); + await waitForRenderingUpdate(); + } + + async function focusAndActivateFirstMarker() { + await resetScrollerStyles(); + await clickAt(15, 15); + assert_equals(getActiveMarker(), 'first', 'click activates the first ::scroll-marker'); + assert_true(markerIsFocused(), 'clicking the first ::scroll-marker focuses it'); + } + + promise_test(async t => { + // Basic LTR navigation sanity check. + // In horizontal-tb: + // Block axis is Top to Bottom. + // Inline axis is Left to Right. + await focusAndActivateFirstMarker(); + await sendKey(kArrowRight); + assert_equals(getActiveMarker(), 'middle', 'right arrow moves forward in horizontal-tb ltr'); + + await focusAndActivateFirstMarker(); + await sendKey(kArrowLeft); + assert_equals(getActiveMarker(), 'last', 'left arrow wraps backward in horizontal-tb ltr'); + + await focusAndActivateFirstMarker(); + await sendKey(kArrowDown); + assert_equals(getActiveMarker(), 'middle', 'down arrow moves forward in horizontal-tb ltr'); + + await focusAndActivateFirstMarker(); + await sendKey(kArrowUp); + assert_equals(getActiveMarker(), 'last', 'up arrow wraps backward in horizontal-tb ltr'); + + // Check that RTL flips the behavior of the horizontal arrows. + await focusAndActivateFirstMarker(); + scroller.style.direction = 'rtl'; + await waitForRenderingUpdate(); + assert_true(markerIsFocused(), 'changing to RTL keeps focus on the first ::scroll-marker'); + await sendKey(kArrowRight); + assert_equals(getActiveMarker(), 'last', 'in RTL, right arrow wraps backward'); + + // In RTL, left arrow acts like right arrow in LTR, so it moves forward from first to middle + await focusAndActivateFirstMarker(); + scroller.style.direction = 'rtl'; + await waitForRenderingUpdate(); + await sendKey(kArrowLeft); + assert_equals(getActiveMarker(), 'middle', 'in RTL, left arrow moves forward'); + }, 'Arrow keys in horizontal-tb'); + + promise_test(async t => { + // In vertical-lr: + // Block axis is Left to Right. + // Inline axis is Top to Bottom. + await focusAndActivateFirstMarker(); + scroller.style.writingMode = 'vertical-lr'; + await waitForRenderingUpdate(); + + await sendKey(kArrowDown); + assert_equals(getActiveMarker(), 'middle', 'down arrow moves forward in vertical-lr'); + await sendKey(kArrowUp); + assert_equals(getActiveMarker(), 'first', 'up arrow moves backward in vertical-lr'); + await sendKey(kArrowRight); + assert_equals(getActiveMarker(), 'middle', 'right arrow moves forward in vertical-lr'); + await sendKey(kArrowLeft); + assert_equals(getActiveMarker(), 'first', 'left arrow moves backward in vertical-lr'); + }, 'Arrow keys in vertical-lr'); + + promise_test(async t => { + // In vertical-rl: + // Block axis is Right to Left. + // Inline axis is Top to Bottom. + await focusAndActivateFirstMarker(); + scroller.style.writingMode = 'vertical-rl'; + await waitForRenderingUpdate(); + + await sendKey(kArrowDown); + assert_equals(getActiveMarker(), 'middle', 'down arrow moves forward in vertical-rl'); + await sendKey(kArrowUp); + assert_equals(getActiveMarker(), 'first', 'up arrow moves backward in vertical-rl'); + await sendKey(kArrowRight); + assert_equals(getActiveMarker(), 'last', 'right arrow wraps backward in vertical-rl'); + await sendKey(kArrowLeft); + assert_equals(getActiveMarker(), 'first', 'left arrow moves forward in vertical-rl'); + }, 'Arrow keys in vertical-rl'); + + promise_test(async t => { + // In vertical-rl with rtl direction: + // Block axis is Right to Left. + // Inline axis is Bottom to Top. + await focusAndActivateFirstMarker(); + scroller.style.writingMode = 'vertical-rl'; + scroller.style.direction = 'rtl'; + await waitForRenderingUpdate(); + + await sendKey(kArrowDown); + assert_equals(getActiveMarker(), 'last', 'down arrow wraps backward in vertical-rl rtl'); + await sendKey(kArrowUp); + assert_equals(getActiveMarker(), 'first', 'up arrow moves forward in vertical-rl rtl'); + await sendKey(kArrowLeft); + assert_equals(getActiveMarker(), 'middle', 'left arrow moves forward in vertical-rl rtl'); + await sendKey(kArrowRight); + assert_equals(getActiveMarker(), 'first', 'right arrow moves backward in vertical-rl rtl'); + }, 'Arrow keys in vertical-rl rtl'); + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-selection-picks-closest.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-selection-picks-closest.html index e0e46ba1d425..3f7ac296e785 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-selection-picks-closest.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-selection-picks-closest.html @@ -8,7 +8,7 @@ - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-active-element.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-active-element.html index 0b2d68b5773f..89d6f64de23d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-active-element.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-active-element.html @@ -1,6 +1,6 @@ -CSS Test: document.activeElement for ::scroll-marker is scroller +CSS Test: document.activeElement for ::scroll-marker in links and tabs modes @@ -56,12 +56,25 @@
\ No newline at end of file + assert_equals(document.activeElement, scroller, "document.activeElement for ::scroll-marker is scroller in tabs mode"); + }, "document.activeElement for ::scroll-marker is document.body in links mode, and scroller in tabs mode"); + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-on-scrolling.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-on-scrolling.html index 8e5851a49735..8278771a237e 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-on-scrolling.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-on-scrolling.html @@ -1,6 +1,6 @@ -CSS Test: scroll tracking for ::scroll-marker +CSS Test: scroll tracking for ::scroll-marker in links and tabs modes @@ -62,10 +62,34 @@ " but was " + pseudoOpacity.toString()); } promise_test(async () => { + // 1. Links mode (default) scroller.scrollTop = 150; assertPseudoElementProperty(target, "::scroll-marker", "1"); - }, "active ::scroll-marker doesn't have focus on scroll if previous ::scroll-marker didn't have it"); + }, "active ::scroll-marker doesn't have focus on scroll if previous ::scroll-marker didn't have it in links mode"); + promise_test(async () => { + // 1. Links mode (default) + /* Click the first ::scroll-marker to attempt to give it focus. */ + let actions_promise = new test_driver.Actions() + .pointerMove(7, 7) + .pointerDown() + .pointerUp() + .pointerDown() + .pointerUp() + .send(); + await actions_promise; + await waitForAnimationFrames(2); + scroller.scrollTop = 150; + await waitForAnimationFrames(2); + assertPseudoElementProperty(target, "::scroll-marker", "1"); + }, "active ::scroll-marker does not save focus on scroll in links mode because click does not focus the marker"); + + promise_test(async () => { + // 2. Tabs mode + document.activeElement.blur(); + scroller.style.setProperty("scroll-marker-group", "before tabs"); + await waitForAnimationFrames(2); + /* Click the first ::scroll-marker to give it focus. */ let actions_promise = new test_driver.Actions() .pointerMove(7, 7) @@ -79,5 +103,5 @@ scroller.scrollTop = 150; await waitForAnimationFrames(2); assertPseudoElementProperty(target, "::scroll-marker", "0.5"); - }, "active ::scroll-marker saves focus on scroll if previous ::scroll-marker had it"); + }, "active ::scroll-marker saves focus on scroll if previous ::scroll-marker had it in tabs mode"); diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-nested-scrollers.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-nested-scrollers.html new file mode 100644 index 000000000000..35f00da9bb3a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-nested-scrollers.html @@ -0,0 +1,87 @@ + + +CSS Overflow Test: scroll tracking for ::scroll-marker in nested scrollers + + + + + +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-014.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-014.html new file mode 100644 index 000000000000..45cbd057c2b5 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-014.html @@ -0,0 +1,76 @@ + +CSS Overflow: scroll-target-group: auto with container-type: inline-size + + + + + +
+
+
Section 1
+
Section 2
+
Section 3
+
+
+ \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-iframe.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-iframe.html new file mode 100644 index 000000000000..049dec61c30a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-iframe.html @@ -0,0 +1,81 @@ + +CSS Overflow: scroll-target-group: auto with iframe sibling + + + + + +
+
Section 1
+ +
Section 2
+
Section 3
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/support/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/support/w3c-import.log index 3395d31b8cf9..1dc4bec0bf95 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/support/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/support/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/support/scroll-marker-support.js diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-expected.html index e4dbe28a85a9..033f34d27002 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-expected.html @@ -20,7 +20,6 @@ overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; @@ -38,13 +37,15 @@ margin: 3px; background-color: red; } - /* item 2 is child 3 */ + /* item2 is child 3. item2.scrollIntoView aligns to its center. */ + & > :nth-child(3) { + scroll-snap-align: center; + } & > :nth-child(3)::scroll-marker { background-color: green; } &>.item { - scroll-snap-align: center; height: 80%; width: 158px; border: 1px solid; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-ref.html index e4dbe28a85a9..033f34d27002 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001-ref.html @@ -20,7 +20,6 @@ overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; @@ -38,13 +37,15 @@ margin: 3px; background-color: red; } - /* item 2 is child 3 */ + /* item2 is child 3. item2.scrollIntoView aligns to its center. */ + & > :nth-child(3) { + scroll-snap-align: center; + } & > :nth-child(3)::scroll-marker { background-color: green; } &>.item { - scroll-snap-align: center; height: 80%; width: 158px; border: 1px solid; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001.html index a9b79ae1d097..46e7f839a8c7 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-001.html @@ -24,7 +24,6 @@ overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-expected.html index 6f28d562d9c9..b82ec1b35a24 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-expected.html @@ -51,9 +51,8 @@ display: inline-block; } - /* Item 3 is child 4. Starting from scrollLeft=0, calling - box4.scrollIntoView ends up in a position that aligns box 3. */ - & > :nth-child(4){ + /* item4 is child 5. item4.scrollIntoView aligns to its center. */ + & > :nth-child(5){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-ref.html index 6f28d562d9c9..b82ec1b35a24 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002-ref.html @@ -51,9 +51,8 @@ display: inline-block; } - /* Item 3 is child 4. Starting from scrollLeft=0, calling - box4.scrollIntoView ends up in a position that aligns box 3. */ - & > :nth-child(4){ + /* item4 is child 5. item4.scrollIntoView aligns to its center. */ + & > :nth-child(5){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002.html index 08c3a302a549..8acb21284ff5 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-002.html @@ -24,7 +24,6 @@ overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-expected.html index 4ead4f45813a..1c2310112f5f 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-expected.html @@ -15,7 +15,7 @@ } .carousel { - width: 800px; + width: 500px; height: 200px; overflow-x: scroll; scroll-snap-type: x mandatory; @@ -68,15 +68,14 @@ &>.item { scroll-snap-align: none; height: 80%; - width: 158px; + width: 80px; border: 1px solid; place-content: center; display: inline-block; } - /* Make only item 16 (index 15) a snap target so we are scrolled all the - way to the right edge */ - & > :nth-child(14){ + /* item14 is child 15. item14.scrollIntoView() aligns to its center. */ + & > :nth-child(15){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-ref.html index 4ead4f45813a..1c2310112f5f 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003-ref.html @@ -15,7 +15,7 @@ } .carousel { - width: 800px; + width: 500px; height: 200px; overflow-x: scroll; scroll-snap-type: x mandatory; @@ -68,15 +68,14 @@ &>.item { scroll-snap-align: none; height: 80%; - width: 158px; + width: 80px; border: 1px solid; place-content: center; display: inline-block; } - /* Make only item 16 (index 15) a snap target so we are scrolled all the - way to the right edge */ - & > :nth-child(14){ + /* item14 is child 15. item14.scrollIntoView() aligns to its center. */ + & > :nth-child(15){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003.html index 4f8f68646ded..845c5a8e3431 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-003.html @@ -19,12 +19,11 @@ } .carousel { - width: 800px; + width: 500px; height: 200px; overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; @@ -58,7 +57,7 @@ &>.item { scroll-snap-align: center; height: 80%; - width: 158px; + width: 80px; border: 1px solid; place-content: center; display: inline-block; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-expected.html index 6e42518107cf..69f872308731 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-expected.html @@ -77,10 +77,8 @@ display: inline-block; } - /* The test calls scrollIntoView on item 13 (child 14). Make only item 11 - (index 12) a snap target as it is what is aligned when scrollintoView - is called on item 13. */ - & > :nth-child(12){ + /* item13 is child 14. item13.scrollIntoView aligns to its center. */ + & > :nth-child(14){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-ref.html index 6e42518107cf..69f872308731 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-ref.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004-ref.html @@ -77,10 +77,8 @@ display: inline-block; } - /* The test calls scrollIntoView on item 13 (child 14). Make only item 11 - (index 12) a snap target as it is what is aligned when scrollintoView - is called on item 13. */ - & > :nth-child(12){ + /* item13 is child 14. item13.scrollIntoView aligns to its center. */ + & > :nth-child(14){ scroll-snap-align: center; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004.html index 60ed33c73b67..acc8f2ed011c 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/targeted-column-scroll-marker-selection-004.html @@ -24,7 +24,6 @@ overflow-x: scroll; scroll-snap-type: x mandatory; list-style-type: none; - scroll-behavior: smooth; border: solid 2px grey; padding-top: 10%; text-align: center; diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/w3c-import.log index fbb9ae657c8d..71db5a56ff8f 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/w3c-import.log @@ -10,11 +10,9 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: -/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yaml +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/WEB_FEATURES.yml /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/chrome-421199213-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/column-scroll-marker-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/column-scroll-marker-001-ref.html @@ -88,6 +86,9 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-on-object-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-on-object-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-on-object.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position-ref.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-reattachment-position.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-button-universal-before.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-buttons-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-buttons-001-ref.html @@ -261,6 +262,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-in-display-none-column-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-001.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-002.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-inert-003.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-multiple-activation.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-navigation-cycles.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-marker-next-focus.html @@ -282,6 +284,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-focus-on-scrolling.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-inside-canvas-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-inside-select-crash.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-nested-scrollers.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-resize-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-under-content-visibility-auto-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-markers-under-content-visibility-auto-ref.html @@ -319,6 +322,8 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-012-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-012.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-013.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-014.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-iframe.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-inline-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-inline-targets-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scroll-markers/scroll-target-group-inline-targets-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scrollbar-gutter-zero-width-crash.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scrollbar-gutter-zero-width-crash.html new file mode 100644 index 000000000000..7f1fce431d9a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/scrollbar-gutter-zero-width-crash.html @@ -0,0 +1,16 @@ + + +CSS Overflow: zero-width scroller with scrollbar-gutter should not crash + + + +
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-expected.html new file mode 100644 index 000000000000..14f3b8663a55 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-expected.html @@ -0,0 +1,25 @@ + + +Single-axis scroll containers: Clipped X Rendering RTL (Reference) + + +
+
RTL gradient and text
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-ref.html new file mode 100644 index 000000000000..14f3b8663a55 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl-ref.html @@ -0,0 +1,25 @@ + + +Single-axis scroll containers: Clipped X Rendering RTL (Reference) + + +
+
RTL gradient and text
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl.html new file mode 100644 index 000000000000..46786aa24690 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-clip-rtl.html @@ -0,0 +1,25 @@ + + +Single-axis scroll containers: Clipped X Rendering RTL + + + +
+
RTL gradient and text
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-expected.html new file mode 100644 index 000000000000..a87f5c67fac6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-expected.html @@ -0,0 +1,43 @@ + + + + + Visual clamp single-axis overflow: scroll to clip on dynamic style changes (Reference) + + + +
+
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-ref.html new file mode 100644 index 000000000000..a87f5c67fac6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip-ref.html @@ -0,0 +1,43 @@ + + + + + Visual clamp single-axis overflow: scroll to clip on dynamic style changes (Reference) + + + +
+
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip.html new file mode 100644 index 000000000000..8d7e84aeba0e --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-overflow-scroll-to-clip.html @@ -0,0 +1,91 @@ + + + + + Single-axis scroll containers visually clamp disabled axes on dynamic style changes + + + + + + + +
+
+
+
+
+
+
+
+ + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic-expected.txt new file mode 100644 index 000000000000..e96c7307d018 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic-expected.txt @@ -0,0 +1,3 @@ + +FAIL changing from overflow: hidden to a single-axis scroller clamps the disabled axis and its scroll dimensions assert_equals: expected 0 but got 50 + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic.html new file mode 100644 index 000000000000..92b890a48951 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-dynamic.html @@ -0,0 +1,51 @@ + + +Single-axis scroll containers clamp disabled axes on dynamic style changes + + + + + + + +
+
+ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic-expected.txt new file mode 100644 index 000000000000..fa562ff7d0b3 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic-expected.txt @@ -0,0 +1,6 @@ + +FAIL LTR clipped X assert_equals: LTR clipped X: scrollTo ignores the clipped X-axis expected 0 but got 40 +FAIL RTL clipped X assert_equals: RTL clipped X: scrollTo ignores the clipped X-axis (negative in RTL) expected 0 but got -40 +FAIL LTR clipped Y assert_equals: LTR clipped Y: scrollTo ignores the clipped Y-axis expected 0 but got 50 +FAIL RTL clipped Y assert_equals: RTL clipped Y: scrollTo ignores the clipped Y-axis expected 0 but got 50 + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic.html new file mode 100644 index 000000000000..1f8d95b4fa49 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-apis-programmatic.html @@ -0,0 +1,161 @@ + + +Single-axis scroll containers with programmatic scroll APIs + + + + + + + + + + + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-expected.txt new file mode 100644 index 000000000000..e9a21f7ff911 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-expected.txt @@ -0,0 +1,3 @@ + +FAIL scrollIntoView() respects single-axis limits independently on each ancestor assert_equals: inner ignores the clipped vertical axis expected 0 but got 20 + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl-expected.txt new file mode 100644 index 000000000000..48d36a180a1c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl-expected.txt @@ -0,0 +1,3 @@ + +FAIL scrollIntoView() respects single-axis limits independently on each ancestor in RTL assert_equals: inner ignores the clipped vertical axis expected 0 but got 20 + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl.html new file mode 100644 index 000000000000..56cfe21c3350 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view-rtl.html @@ -0,0 +1,77 @@ + + +Single-axis scroll containers with scrollIntoView (RTL) + + + + + + + +
+ +
+
+
+
+
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view.html new file mode 100644 index 000000000000..aba04f8fe9b2 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/single-axis-scroll-into-view.html @@ -0,0 +1,76 @@ + + +Single-axis scroll containers with scrollIntoView + + + + + + + +
+ +
+
+
+
+
+
+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001.html similarity index 88% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001.html index ae9029933a6a..2fdcf8233e8a 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001.html @@ -3,7 +3,7 @@ CSS Basic User Interface Test: text-overflow - clip - the text inline content overflows will be broken - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002.html similarity index 88% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002.html index d8a95299d29d..717c508eb019 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002.html @@ -3,7 +3,7 @@ CSS Basic User Interface Test: text-overflow - ellipsis - the broken textual content instead of ellipsis - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003.html similarity index 88% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003.html index ea958ef35b15..8c7ea45fad13 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003.html @@ -3,7 +3,7 @@ CSS Basic User Interface Test: text-overflow - inherit - inherit clip value of parent's text-overflow property - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004.html similarity index 89% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004.html index 1cc11e82573a..760fd685c20b 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004.html @@ -3,7 +3,7 @@ CSS Basic User Interface Test: text-overflow - inherit - inherit ellipsis value of parent's text-overflow property - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005.html similarity index 86% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005.html index b7ced3673dce..72d29577e1da 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005.html @@ -4,7 +4,7 @@ CSS-UI test: text-overflow reflow - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-006-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-006-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-006.html similarity index 93% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-006.html index 8fd149a98db0..238a17be2ae1 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-006.html @@ -2,7 +2,7 @@ CSS Basic User Interface Test: text-overflow applied at edge of block container - + + + +

Test passes if there is a filled green square and no red.

+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-007.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-007.html similarity index 95% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-007.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-007.html index 795dae40fa4a..5b14dd334b99 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-007.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-007.html @@ -2,7 +2,7 @@ CSS Basic User Interface Test: ellipsis adjacent to remaining content - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-008-expected.html similarity index 100% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-008-expected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-008.html similarity index 71% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-008.html index e4dbd761a05d..2128179174f2 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-008.html @@ -2,13 +2,13 @@ CSS Basic User Interface Test: ellipsis and first character - + + + +

Test passes if there is a filled green square and no red.

+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-009.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-009.html similarity index 90% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-009.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-009.html index 384f82051199..d8ea68f38368 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-009.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-009.html @@ -2,7 +2,7 @@ CSS Basic User Interface Test: ellipsis and first atomic inline - + + + +

Test passes if there is a filled green square and no red.

+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-010.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-010.html similarity index 94% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-010.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-010.html index aec768cb6979..687d20cef9fc 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-010.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-010.html @@ -2,7 +2,7 @@ CSS Basic User Interface Test: ellipsis hides atomic inlines and chars at end of line - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011-expected.xht b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011-expected.xht new file mode 100644 index 000000000000..05a13794482a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011-expected.xht @@ -0,0 +1,19 @@ + + + + CSS Reftest Reference + + + + +

Test passes if there is a filled green square and no red.

+
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-011.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011.html similarity index 93% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-011.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011.html index 0fe96e65193b..6392a51a412d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-011.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011.html @@ -2,7 +2,7 @@ CSS Basic User Interface Test: ellipsis hides end of line - + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012-expected.html similarity index 95% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012-expected.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012-expected.html index 700f9c896fe9..707f93d79c49 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012-expected.html @@ -9,7 +9,7 @@ color: green; } span { - color: white; + color: white; } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012.html similarity index 95% rename from LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012.html rename to LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012.html index a75908026aa3..15e31deda7d6 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-overflow/text-overflow-012.html @@ -3,7 +3,7 @@ CSS Basic User Interface Test: ellipsis and extended grapheme cluster - + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027-expected.html new file mode 100644 index 000000000000..4ef861117d64 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration 4 reference: text-decoration-inset calc + + + + +

abcdefghij  

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027.html new file mode 100644 index 000000000000..8bb94fe9fe49 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027.html @@ -0,0 +1,21 @@ + + +CSS Text Decoration 4: text-decoration-inset calc + + + + + + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028-expected.html new file mode 100644 index 000000000000..ab565c274e7b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028-expected.html @@ -0,0 +1,18 @@ + + +CSS Text Decoration 4 reference: text-decoration-inset percentage with b-d-b slice + + + + +
+

abcde fghij

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028.html new file mode 100644 index 000000000000..5360d0e986f2 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028.html @@ -0,0 +1,22 @@ + + +CSS Text Decoration 4: text-decoration-inset percentage with b-d-b slice + + + + + + +
+

abcde fghij

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029-expected.html new file mode 100644 index 000000000000..2411a16c7519 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029-expected.html @@ -0,0 +1,18 @@ + + +CSS Text Decoration 4 reference: text-decoration-inset percentage with b-d-b clone + + + + +
+

abcde fghij

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029.html new file mode 100644 index 000000000000..d8e512dfafd3 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029.html @@ -0,0 +1,22 @@ + + +CSS Text Decoration 4: text-decoration-inset percentage with b-d-b clone + + + + + + +
+

abcde fghij

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030-expected.html new file mode 100644 index 000000000000..ab565c274e7b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030-expected.html @@ -0,0 +1,18 @@ + + +CSS Text Decoration 4 reference: text-decoration-inset percentage with b-d-b slice + + + + +
+

abcde fghij

+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030.html new file mode 100644 index 000000000000..7ffe4c77752b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030.html @@ -0,0 +1,20 @@ + + +CSS Text Decoration 4: text-decoration-inset percentage with b-d-b slice and br + + + + + + +

abcde
fghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone-expected.html new file mode 100644 index 000000000000..1fb80ae660c9 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration: with box-decoration-break: clone a percentage inset resolves per fragment (reference) + + + +
abcde fghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone.html new file mode 100644 index 000000000000..fe1541738e31 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-clone.html @@ -0,0 +1,23 @@ + + +CSS Text Decoration: with box-decoration-break: clone a percentage inset resolves per fragment + + + + + + + + + +
abcde fghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence-expected.html new file mode 100644 index 000000000000..f4fe7cda170c --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration: a percentage text-decoration-inset matches the equivalent length (reference) + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence.html new file mode 100644 index 000000000000..45a0c7fce0fa --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-equivalence.html @@ -0,0 +1,21 @@ + + +CSS Text Decoration: a percentage text-decoration-inset matches the equivalent length + + + + + + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-expected.html new file mode 100644 index 000000000000..af15780a9f19 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration: a negative percentage text-decoration-inset extends the decoration (reference) + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow-expected.html new file mode 100644 index 000000000000..ec38f4be666d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow-expected.html @@ -0,0 +1,17 @@ + + +CSS Text Decoration: growing a negative percentage inset re-expands the ink overflow (reference) + + + +
abcdefghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow.html new file mode 100644 index 000000000000..a6c539b51a4b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-grow.html @@ -0,0 +1,35 @@ + + + +CSS Text Decoration: growing a negative percentage inset re-expands the ink overflow + + + + + + + + +
abcdefghij
+ + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental-expected.html new file mode 100644 index 000000000000..b1b69b7bc02b --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental-expected.html @@ -0,0 +1,18 @@ + + +CSS Text Decoration: a negative percentage inset survives an incremental relayout of a later line (reference) + + + +

abcde fghij klmno

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental.html new file mode 100644 index 000000000000..f951ae477231 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-incremental.html @@ -0,0 +1,35 @@ + + + +CSS Text Decoration: a negative percentage inset survives an incremental relayout of a later line + + + + + + + + +

abcde fghij klmnX

+ + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer-expected.html new file mode 100644 index 000000000000..c75c2ac70165 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer-expected.html @@ -0,0 +1,17 @@ + + +CSS Text Decoration: a negative percentage inset is not clipped by a composited layer (reference) + + + +
abcdefghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer.html new file mode 100644 index 000000000000..99184f5a323d --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-layer.html @@ -0,0 +1,22 @@ + + +CSS Text Decoration: a negative percentage inset is not clipped by a composited layer + + + + + + + + +
abcdefghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline-expected.html new file mode 100644 index 000000000000..d51cd255ec85 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline-expected.html @@ -0,0 +1,18 @@ + + +CSS Text Decoration: a negative percentage inset on a multi-line box extends by a percentage of the whole box (reference) + + + +

abcde fghij klmno

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline.html new file mode 100644 index 000000000000..9aa846ed3aa4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-multiline.html @@ -0,0 +1,25 @@ + + +CSS Text Decoration: a negative percentage inset on a multi-line box extends by a percentage of the whole box + + + + + + + + +

abcde fghij klmno

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated-expected.html new file mode 100644 index 000000000000..eebe60bde18e --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated-expected.html @@ -0,0 +1,20 @@ + + +CSS Text Decoration: a negative percentage inset extends a decoration that propagates to a descendant (reference) + + + + +
abcdefghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated.html new file mode 100644 index 000000000000..cb71af656148 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-propagated.html @@ -0,0 +1,26 @@ + + +CSS Text Decoration: a negative percentage inset extends a decoration that propagates to a descendant + + + + + + + + +
abcdefghij
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint-expected.html new file mode 100644 index 000000000000..ac4e5739619f --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration: a negative percentage inset repaints its overhang on a dynamic change (reference) + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint.html new file mode 100644 index 000000000000..23534aa241bf --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative-repaint.html @@ -0,0 +1,33 @@ + + + +CSS Text Decoration: a negative percentage inset repaints its overhang on a dynamic change + + + + + + + + +

abcdefghij

+ + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative.html new file mode 100644 index 000000000000..15b8ca64d260 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-negative.html @@ -0,0 +1,21 @@ + + +CSS Text Decoration: a negative percentage text-decoration-inset extends the decoration + + + + + + + + +

abcdefghij

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding-expected.html new file mode 100644 index 000000000000..38a7b74b95a9 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding-expected.html @@ -0,0 +1,21 @@ + + +CSS Text Decoration: a percentage inset resolves against the decorating box including its padding (reference) + + + + + +
aaaabbbb
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding.html new file mode 100644 index 000000000000..8d693e1a6160 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-padding.html @@ -0,0 +1,27 @@ + + +CSS Text Decoration: a percentage inset resolves against the decorating box including its padding + + + + + + + + +
aaaabbbb
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-expected.html new file mode 100644 index 000000000000..04c43d55866a --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-expected.html @@ -0,0 +1,14 @@ + + +Reference: percentage text-decoration-inset resolves against the whole decorated run with box-decoration-break: slice + +
ABCD
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline-expected.html new file mode 100644 index 000000000000..3ac42704c055 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline-expected.html @@ -0,0 +1,16 @@ + + +Reference: percentage text-decoration-inset over three line fragments + + +

abcde fghij klmno

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline.html new file mode 100644 index 000000000000..63d1166959c3 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline.html @@ -0,0 +1,25 @@ + + +CSS Text Decoration 4: percentage text-decoration-inset over three line fragments + + + + + + +

abcde fghij klmno

diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice.html new file mode 100644 index 000000000000..6587a92fbf03 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice.html @@ -0,0 +1,22 @@ + + + +CSS Text Decoration 4: percentage text-decoration-inset resolves against the whole decorated run with box-decoration-break: slice + + + + + +
ABCD
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow-expected.html new file mode 100644 index 000000000000..6fbe17892ee5 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow-expected.html @@ -0,0 +1,16 @@ + + +CSS Text Decoration: a decoration propagated to a descendant inline box is measured with the originating box's style (reference) + + + + +
thickness
+
wavyline
+
negative inset
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow.html new file mode 100644 index 000000000000..e13bd3f57265 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagated-ink-overflow.html @@ -0,0 +1,23 @@ + + +CSS Text Decoration: a decoration propagated to a descendant inline box is measured with the originating box's style + + + + + + + +
thickness
+
wavyline
+
negative inset
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/w3c-import.log index 06cd8872a6ba..cb15c4f39bdb 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/w3c-import.log @@ -89,8 +89,22 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-024.html /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-025-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-025.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-026-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-026.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-027.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-028.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-029.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-030.html /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-orthogonal-block-001-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-orthogonal-block-001.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline-expected.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice-multiline.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-inset-percentage-slice.html /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-line-010-expected.xht /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-line-010.xht /LayoutTests/imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-line-011-expected.xht diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation-expected.txt new file mode 100644 index 000000000000..8df21383d165 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation-expected.txt @@ -0,0 +1,3 @@ + +PASS Canceling a transition with transition-duration set to infinite value + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation.html new file mode 100644 index 000000000000..0db5049ff0b9 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/transition-duration-infinite-cancelation.html @@ -0,0 +1,46 @@ + + + +Canceling a transition with transition-duration set to infinite value + + + + + + + + +
+ + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow-expected.txt index e18deeb40d5e..e69633d96be6 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow-expected.txt @@ -34,6 +34,6 @@ PASS Setting 'text-overflow' to a transform: translate(50%, 50%) throws TypeErro PASS Setting 'text-overflow' to a transform: perspective(10em) throws TypeError PASS Setting 'text-overflow' to a transform: translate3d(0px, 1px, 2px) translate(0px, 1px) rotate3d(1, 2, 3, 45deg) rotate(45deg) scale3d(1, 2, 3) scale(1, 2) skew(1deg, 1deg) skewX(1deg) skewY(45deg) perspective(1px) matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) matrix(1, 2, 3, 4, 5, 6) throws TypeError FAIL 'text-overflow' does not support 'clip ellipsis' assert_class_string: Unsupported value must be a CSSStyleValue and not one of its subclasses expected "[object CSSStyleValue]" but got "[object Undefined]" -FAIL 'text-overflow' does not support '"..."' assert_class_string: Unsupported value must be a CSSStyleValue and not one of its subclasses expected "[object CSSStyleValue]" but got "[object Undefined]" +PASS 'text-overflow' does not support '"..."' FAIL 'text-overflow' does not support 'fade(1px, 50%)' assert_class_string: Unsupported value must be a CSSStyleValue and not one of its subclasses expected "[object CSSStyleValue]" but got "[object Undefined]" diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/WEB_FEATURES.yml index 431c3dd86a52..b2f128bd0193 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/WEB_FEATURES.yml @@ -17,9 +17,7 @@ rules: - caret-shape-*: [caret-shape] - caret-eol-*: [caret-shape] - cursor-image-016-manual.html: [cross-fade, cursor] -- text-overflow-string-*: [custom-ellipses, text-overflow] - native-appearance-disabled-for-value-unset.html: [unset-value] -- text-overflow-*: [text-overflow] - canvas-cursor-*: [cursor] - cursor-*: [cursor] - select-cursor-*: [cursor] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/w3c-import.log index 8dbd4183ad7c..a38cabc747ff 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/w3c-import.log @@ -21,6 +21,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/cursor-no-interpolation.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-color-interpolation.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-composition.html +/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation-rounding.tentative.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-width-composition.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-width-interpolation.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/w3c-import.log index 46851bbb1626..9595ce42b6d2 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/w3c-import.log @@ -12,9 +12,7 @@ Properties requiring vendor prefixes: None ------------------------------------------------------------------------ List of files: -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/WEB_FEATURES.yml /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/chrome-bug-467732064.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/cursor-light-dark-generated-image-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/input-range-content-url.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/outline-scrollIntoView-crash.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/crashtests/text-overflow-ellipsis-multiline-crash.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/WEB_FEATURES.yml index dd510909558e..a45148595cc1 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/WEB_FEATURES.yml @@ -7,5 +7,4 @@ rules: - outline-color-*: [outlines] - outline-offset-*: [outlines] - cursor-*: [cursor] -- text-overflow-*: [text-overflow] - box-sizing-*: [box-sizing] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed-expected.txt deleted file mode 100644 index b255e566ee7f..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed-expected.txt +++ /dev/null @@ -1,4 +0,0 @@ - -PASS Property text-overflow value 'clip' -PASS Property text-overflow value 'ellipsis' - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed.html deleted file mode 100644 index 701506e617b1..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - -CSS UI Level 3: getComputedStyle().textOverflow - - - - - - - -
- - - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid-expected.txt deleted file mode 100644 index 41d88dcf1198..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid-expected.txt +++ /dev/null @@ -1,4 +0,0 @@ - -PASS e.style['text-overflow'] = "auto" should not set the property value -PASS e.style['text-overflow'] = "clip ellipsis clip" should not set the property value - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid.html deleted file mode 100644 index aa4169c1462b..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - -CSS UI Level 3: parsing text-overflow with invalid values - - - - - - - - - - - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid-expected.txt deleted file mode 100644 index db0f4d89fa56..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid-expected.txt +++ /dev/null @@ -1,4 +0,0 @@ - -PASS e.style['text-overflow'] = "clip" should set the property value -PASS e.style['text-overflow'] = "ellipsis" should set the property value - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid.html deleted file mode 100644 index 5d40b6839def..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - -CSS UI Level 3: parsing text-overflow with valid values - - - - - - - - - - - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/w3c-import.log index 97a6e8eead56..8d48600cbd25 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/w3c-import.log @@ -46,9 +46,6 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/resize-computed.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/resize-invalid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/resize-valid.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-computed.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-invalid.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/text-overflow-valid.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/user-select-computed-contain.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/user-select-computed.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/parsing/user-select-invalid.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/w3c-import.log index 0ab18153c5de..651cb3e84efc 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/w3c-import.log @@ -40,30 +40,5 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/outline-style-014-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/outline-with-padding-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/subpixel-outline-width-ref.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-001-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-002-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-005-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-006-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-008-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-012-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-013-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-016-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-021-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-022-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-027-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-028-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-029-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-030-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-change-color-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-indent-001-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-001-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-002-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-003-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-004-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-005-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-006-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-007-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/text-overflow-string-008-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/transparent-accent-color-001-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/reference/transparent-accent-color-002-ref.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select-expected.txt new file mode 100644 index 000000000000..b6e131bac86f --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select-expected.txt @@ -0,0 +1,4 @@ +Button under test + +PASS CSS user-select default value for button element + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select.html new file mode 100644 index 000000000000..f1288c1895c4 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select.html @@ -0,0 +1,17 @@ + + +CSS user-select default value for button element + + + + + + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/w3c-import.log index 3cf9e3deffbd..75b912f63602 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/w3c-import.log @@ -12,6 +12,7 @@ Properties requiring vendor prefixes: user-modify ------------------------------------------------------------------------ List of files: +/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/button-user-select.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/moz-user-modify-01.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/moz-user-modify-02.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/tentative/moz-user-modify-03.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-expected.html deleted file mode 100644 index b471cf1c3163..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-expected.html +++ /dev/null @@ -1,17 +0,0 @@ - - - CSS Reftest Ellipsis Reference - - - - -

PREREQUISITE: The font used must have a glyph for the U+2026 character.

-

Test passes if there is ellipsis after a black square.

-
- A… -
- - \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ref.html deleted file mode 100644 index b471cf1c3163..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ref.html +++ /dev/null @@ -1,17 +0,0 @@ - - - CSS Reftest Ellipsis Reference - - - - -

PREREQUISITE: The font used must have a glyph for the U+2026 character.

-

Test passes if there is ellipsis after a black square.

-
- A… -
- - \ No newline at end of file diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow.html deleted file mode 100644 index 88bc91157b40..000000000000 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow.html +++ /dev/null @@ -1,29 +0,0 @@ - - - CSS Basic User Interface Test: text-overflow - ellipsis - - - - - - - - - - -

PREREQUISITE: The font used must have a glyph for the U+2026 character.

-

Test passes if there is ellipsis after a black square.

-
- AAAA -
- - diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-001.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-001.html index 03796aa8677b..35febc38bb0b 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-001.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-001.html @@ -15,11 +15,11 @@ - +
Let's select this word
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button-expected.txt index ba57a87d1562..eb637e6b1357 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button-expected.txt @@ -7,5 +7,5 @@ PASS the button text should be selectable from outside. PASS the button text should not be selectable from inside when the parent is user-select: text. PASS the button text should be selectable from outside when the parent is user-select: text. PASS the button text should not be selectable from inside when the parent is user-select: none. -FAIL the button text should not be selectable from outside when the parent is user-select: none. assert_equals: expected "" but got "button" +PASS the button text should not be selectable from outside when the parent is user-select: none. diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button.html index 2445537ff252..07c8e1cc3f2a 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-button.html @@ -14,15 +14,15 @@ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-none-on-input.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-none-on-input.html index 7eb82e112d48..f48d9e8a8aa0 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-none-on-input.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/user-select-none-on-input.html @@ -7,7 +7,7 @@ diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/w3c-import.log index c19cc9eba21e..ab6674325eac 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/w3c-import.log @@ -9,7 +9,7 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: -user-select +None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/META.yml @@ -413,98 +413,6 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/select-author-level-padding-applies.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/subpixel-outline-width.tentative-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/subpixel-outline-width.tentative.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-002.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-003.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-004.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-005.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-006.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-007-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-007.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-008.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-009-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-009.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-010-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-010.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-011-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-011.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-012.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-013-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-013.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-014-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-014.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-015-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-015.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-016-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-016.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-017.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-020-expected.xht -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-020.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-021-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-021.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-022-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-022.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-023.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-024-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-024-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-024.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-025-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-025-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-025.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-026-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-026-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-026.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-027-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-027.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-028-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-029-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-029.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-030-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-030.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-change-color-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-change-color.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-abspos-in-inline-block-crash-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-hyphen.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-indent-001-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-indent-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-multiline-001-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-multiline-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-self-painting.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ellipsis-width-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ruby-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ruby-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-ruby.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-001-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-001.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-002-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-002.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-003-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-003.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-004-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-004.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-005-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-005.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-006-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-006.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-007-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-007.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-008-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-string-008.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-with-selection-expected.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-with-selection-ref.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow-with-selection.html -/LayoutTests/imported/w3c/web-platform-tests/css/css-ui/text-overflow.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/translucent-outline-expected.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/translucent-outline-ref.html /LayoutTests/imported/w3c/web-platform-tests/css/css-ui/translucent-outline.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative-expected.txt index b341c138fc4d..f8f2486a6595 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative-expected.txt @@ -7,4 +7,11 @@ PASS random() in same registered function same locals different positions FAIL random() in different function same default locals assert_true: expected true got false FAIL random() in function in local overrides argument assert_false: Random values should not be equal expected false got true PASS random() in function argument +PASS random(fixed) outside a function +PASS random(fixed) through an untyped argument +PASS random(fixed) through a typed argument +FAIL random(fixed) through an untyped argument into a typed result assert_equals: expected "50" but got "0" +FAIL random(fixed) in an untyped local substituted into a typed result assert_equals: expected "50" but got "0" +FAIL random(fixed) in a typed parameter default assert_equals: expected "50" but got "0" +PASS random(fixed) written in a typed result diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative.html index 818f48c33165..bd68306c0386 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative.html +++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/random-in-custom-function.tentative.html @@ -67,6 +67,29 @@ @function --g-number() returns { result: random(--foo property-index-scoped, 1, 1e6); } + + /* random(fixed ) bypasses the random cache name entirely, so the + cases below test only whether a value is produced at all, independent of + how cache names are scoped inside custom functions. Each resolves to 50. */ + @function --fixed-untyped(--x) { + result: var(--x); + } + @function --fixed-typed-argument(--x ) returns { + result: var(--x); + } + @function --fixed-untyped-argument-typed-result(--x) returns { + result: var(--x); + } + @function --fixed-untyped-local-typed-result() returns { + --x: random(fixed 0.5, 0, 100); + result: var(--x); + } + @function --fixed-typed-default(--x : random(fixed 0.5, 0, 100)) returns { + result: var(--x); + } + @function --fixed-typed-result() returns { + result: random(fixed 0.5, 0, 100); + } diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/WEB_FEATURES.yml index e4c0f6ec3087..e8b9513e7cce 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/WEB_FEATURES.yml @@ -1,73 +1,42 @@ -features: -- name: selectors - files: - - attribute.html - - class-id-attr.html - - sibling.html - - insert-sibling-* - - selectorText-dynamic-001.html - - sheet-going-away-* -- name: has - files: - - has-* - - "*-in-has.*" - - "*-in-has-*" -- name: link-selectors - files: - - "any-link-*" -- name: media-pseudos - files: - - media-loading-pseudo-classes-in-has.sub.html - - media-pseudo-classes-in-has.html -- name: modal - files: - - modal-pseudo-class-in-has.html -- name: not - files: - - not-* -- name: nth-child - files: - - first-child-last-child.html - - nth-child-in-shadow-root.html -- name: nth-child-of - files: - - nth-child-of-* - - nth-child-when-* - - nth-child-whole-subtree.html - - nth-child-containing-ancestor.html - - negated-nth-child-when-* - - nth-last-child-of-* - - nth-last-child-when-* - - nth-last-child-containing-ancestor.html - - negated-nth-last-child-when-* -- name: nth-of-type - files: - - 'negated-*-of-type*' -- name: user-pseudos - files: - - user-valid-user-invalid.html -- name: state - files: - - state-in-has.html -- name: placeholder-shown - files: - - placeholder-shown.html -- name: shadow-parts - files: - - part-dir.html - - part-lang.html - - part-pseudo.html -- name: host - files: - - host-* - - "!host-context-*" -- name: is - files: - - is.html - - negated-is-* -- name: where - files: - - where.html -- name: input-selectors - files: - - enabled-disabled.html +rules: +- attribute.html: [selectors] +- class-id-attr.html: [selectors] +- sibling.html: [selectors] +- insert-sibling-*: [selectors] +- selectorText-dynamic-001.html: [selectors] +- sheet-going-away-*: [selectors] +- has-*: [has] +- "*-in-has-*": [has, has] +- media-loading-pseudo-classes-in-has.sub.html: [media-pseudos, has] +- media-pseudo-classes-in-has.html: [media-pseudos, has] +- modal-pseudo-class-in-has.html: [modal, has] +- not-pseudo-containing-sibling-relationship-in-has.html: [has, not] +- not-pseudo-containing-complex-in-has.html: [has, not] +- state-in-has.html: [state, has] +- host-pseudo-class-in-has.html: [has, host] +- host-context-pseudo-class-in-has.html: [has] +- "*-in-has.*": [has] +- any-link-*: [link-selectors] +- not-*: [not] +- first-child-last-child.html: [nth-child] +- nth-child-in-shadow-root.html: [nth-child] +- nth-child-of-*: [nth-child-of] +- nth-child-when-*: [nth-child-of] +- nth-child-whole-subtree.html: [nth-child-of] +- nth-child-containing-ancestor.html: [nth-child-of] +- negated-nth-child-when-*: [nth-child-of] +- nth-last-child-of-*: [nth-child-of] +- nth-last-child-when-*: [nth-child-of] +- nth-last-child-containing-ancestor.html: [nth-child-of] +- negated-nth-last-child-when-*: [nth-child-of] +- negated-is-*: [is, nth-of-type] +- negated-*-of-type*: [nth-of-type] +- user-valid-user-invalid.html: [user-pseudos] +- placeholder-shown.html: [placeholder-shown] +- part-dir.html: [shadow-parts] +- part-lang.html: [shadow-parts] +- part-pseudo.html: [shadow-parts] +- host-*: [host] +- is.html: [is] +- where.html: [where] +- enabled-disabled.html: [input-selectors] diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/crashtests/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/crashtests/w3c-import.log index 0df60f2c8284..91ee0a84048d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/crashtests/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/crashtests/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/crashtests/has-pseudoclass-only-crash.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/w3c-import.log index a2cacf45b1bb..c906563903b9 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/w3c-import.log @@ -10,8 +10,6 @@ Do NOT modify or remove this file. ------------------------------------------------------------------------ Properties requiring vendor prefixes: None -Property values requiring vendor prefixes: -None ------------------------------------------------------------------------ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/WEB_FEATURES.yml @@ -50,6 +48,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-nested-pseudo-002-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-nested-pseudo-003-crash.html /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-element-expected.xht +/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-element-subject-child-mutation.html /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-element.html /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudoclass-only.html /LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-sibling-insertion-removal.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/moveBefore/script-move-before-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/moveBefore/script-move-before-expected.txt index 6a269137f591..b167f7286f86 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/moveBefore/script-move-before-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/moveBefore/script-move-before-expected.txt @@ -1,4 +1,4 @@ -FAIL Synchronous script execution in HTMLScriptElement during moveBefore should be blocked assert_false: does not define moving steps which allow script execution. expected false got true -FAIL Synchronous script execution in SVGScriptElement during moveBefore should be blocked assert_false: does not define moving steps which allow script execution. expected false got true +PASS Synchronous script execution in HTMLScriptElement during moveBefore should be blocked +PASS Synchronous script execution in SVGScriptElement during moveBefore should be blocked diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/WEB_FEATURES.yml b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/WEB_FEATURES.yml index 416ef6049d11..01c1930231a7 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/WEB_FEATURES.yml +++ b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/WEB_FEATURES.yml @@ -1,4 +1,3 @@ -features: -- name: target - files: - - target-pseudo-after-reinsertion.html +rules: +- target-pseudo-after-adoption.html: [target] +- target-pseudo-after-reinsertion.html: [target] diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption-expected.txt new file mode 100644 index 000000000000..fe6572753e47 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption-expected.txt @@ -0,0 +1,4 @@ +target + +PASS :target should follow the target element back after a round trip through another document. + diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption.html b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption.html new file mode 100644 index 000000000000..47f36fb2c515 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption.html @@ -0,0 +1,32 @@ + + + + + + + +
target
+ + diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-reinsertion-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-reinsertion-expected.txt index a20570c30f17..8fff1f013c79 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-reinsertion-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-reinsertion-expected.txt @@ -1,4 +1,4 @@ target -FAIL :target should match the target element even after it is removed and reinserted. assert_equals: :target should match after reinsertion. expected Element node
target
but got null +PASS :target should match the target element even after it is removed and reinserted. diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/w3c-import.log index db65fbb587e7..249a4f149930 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/w3c-import.log @@ -38,4 +38,5 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-to-anchor-name.html /LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-to-id-top.html /LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/scroll-to-top.html +/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-adoption.html /LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/target-pseudo-after-reinsertion.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target-expected.txt new file mode 100644 index 000000000000..4c9fbed9a341 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target-expected.txt @@ -0,0 +1,3 @@ + +PASS Autofocus should be skipped when the target element has been removed from the document. + diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target.html b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target.html new file mode 100644 index 000000000000..5433fdf51ec6 --- /dev/null +++ b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target.html @@ -0,0 +1,27 @@ + + + + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/w3c-import.log index 8f389afad2c9..65243ba9ca00 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/w3c-import.log @@ -21,6 +21,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/autofocus-on-stable-document.html /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-empty.html /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-nonexistent.html +/LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-removed-target.html /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-valid.html /LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/the-autofocus-attribute/first-reconnected.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-not-highlighted-expected.html b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-not-highlighted-expected.html index 15d632578fcb..1b757ecf62db 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-not-highlighted-expected.html +++ b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/inert-node-is-not-highlighted-expected.html @@ -4,7 +4,7 @@ + + + diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/w3c-import.log index b748b09f5e71..fe8f5c8524bf 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/w3c-import.log +++ b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/w3c-import.log @@ -50,6 +50,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-backdrop-appearance-expected.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-backdrop-appearance-ref.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-backdrop-appearance.html +/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-beforetoggle-change-type-crash.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-beforetoggle-opening-event.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-change-type.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-checkbox-backdrop-expected.html @@ -71,6 +72,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-inert-invoker.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-inside-shadow-dom.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-inside-slot.html +/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-invoker-inside-popover.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-overflow-visible.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-previous-crash.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-slotted.html @@ -83,6 +85,7 @@ List of files: /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-hidden-display.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-hint-crash.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-hint-hierarchy.html +/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-hint-loseinterest-show-child.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-hint-reentrant-crash.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-iframe-backdrop-expected.html /LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-iframe-backdrop.html diff --git a/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/scroll-timeline-name-shadow-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/scroll-timeline-name-shadow-expected.txt index e886fe3918ca..8a64dfdd16f9 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/scroll-timeline-name-shadow-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/scroll-timeline-name-shadow-expected.txt @@ -1,6 +1,6 @@ -FAIL Outer animation can not see scroll timeline defined by :host assert_equals: expected "x" but got "y" -FAIL Outer animation can not see scroll timeline defined by ::slotted assert_equals: expected "x" but got "y" +PASS Outer animation can not see scroll timeline defined by :host +PASS Outer animation can not see scroll timeline defined by ::slotted PASS Inner animation can see scroll timeline defined by ::part PASS Animation inside shadow DOM can see the scroll timeline defined by the ancestor DOM diff --git a/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/view-timeline-name-shadow-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/view-timeline-name-shadow-expected.txt index 99f3418cc8f8..b7de7d0d38a0 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/view-timeline-name-shadow-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/scroll-animations/css/view-timeline-name-shadow-expected.txt @@ -1,6 +1,6 @@ -FAIL Outer animation can not see view timeline defined by :host assert_equals: expected "x" but got "y" -FAIL Outer animation can not see view timeline defined by ::slotted assert_equals: expected "x" but got "y" +PASS Outer animation can not see view timeline defined by :host +PASS Outer animation can not see view timeline defined by ::slotted PASS Inner animation can see view timeline defined by ::part PASS Animation inside shadow DOM can see the view timeline defined by the ancestor DOM diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any-expected.txt index c4629b03f7e1..52cd8eda41f9 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any-expected.txt @@ -1,4 +1,4 @@ -FAIL Local mutable global exports should be live bindings assert_equals: expected (number) 555 but got (object) object "[object WebAssembly.Global]" -FAIL Dep module mutable global exports should be live bindings assert_equals: expected (number) 3001 but got (object) object "[object WebAssembly.Global]" +PASS Local mutable global exports should be live bindings +PASS Dep module mutable global exports should be live bindings diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any.worker-expected.txt index c4629b03f7e1..52cd8eda41f9 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any.worker-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports-live-bindings.tentative.any.worker-expected.txt @@ -1,4 +1,4 @@ -FAIL Local mutable global exports should be live bindings assert_equals: expected (number) 555 but got (object) object "[object WebAssembly.Global]" -FAIL Dep module mutable global exports should be live bindings assert_equals: expected (number) 3001 but got (object) object "[object WebAssembly.Global]" +PASS Local mutable global exports should be live bindings +PASS Dep module mutable global exports should be live bindings diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any-expected.txt index 1913b69f275f..f50fb8118401 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any-expected.txt @@ -1,7 +1,7 @@ PASS WebAssembly module global values should be unwrapped when importing in ESM integration -FAIL WebAssembly mutable global values should be unwrapped when importing in ESM integration assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly local global values should be unwrapped when exporting in ESM integration assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly module globals from imported WebAssembly modules should be unwrapped assert_equals: expected (number) 2001 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly should properly handle all global types assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" +PASS WebAssembly mutable global values should be unwrapped when importing in ESM integration +PASS WebAssembly local global values should be unwrapped when exporting in ESM integration +PASS WebAssembly module globals from imported WebAssembly modules should be unwrapped +PASS WebAssembly should properly handle all global types diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any.worker-expected.txt index 1913b69f275f..f50fb8118401 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any.worker-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/global-exports.tentative.any.worker-expected.txt @@ -1,7 +1,7 @@ PASS WebAssembly module global values should be unwrapped when importing in ESM integration -FAIL WebAssembly mutable global values should be unwrapped when importing in ESM integration assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly local global values should be unwrapped when exporting in ESM integration assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly module globals from imported WebAssembly modules should be unwrapped assert_equals: expected (number) 2001 but got (object) object "[object WebAssembly.Global]" -FAIL WebAssembly should properly handle all global types assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" +PASS WebAssembly mutable global values should be unwrapped when importing in ESM integration +PASS WebAssembly local global values should be unwrapped when exporting in ESM integration +PASS WebAssembly module globals from imported WebAssembly modules should be unwrapped +PASS WebAssembly should properly handle all global types diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any-expected.txt index d665f3fea2ae..fe4e3433a5c7 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any-expected.txt @@ -1,5 +1,5 @@ -FAIL WebAssembly modules should export shared mutable globals with correct initial values assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" +PASS WebAssembly modules should export shared mutable globals with correct initial values PASS Wasm-to-Wasm mutable global sharing is live PASS Multiple JavaScript imports return the same WebAssembly module instance PASS v128 globals should work correctly in WebAssembly-to-WebAssembly imports diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any.worker-expected.txt index d665f3fea2ae..fe4e3433a5c7 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any.worker-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/mutable-global-sharing.tentative.any.worker-expected.txt @@ -1,5 +1,5 @@ -FAIL WebAssembly modules should export shared mutable globals with correct initial values assert_equals: expected (number) 100 but got (object) object "[object WebAssembly.Global]" +PASS WebAssembly modules should export shared mutable globals with correct initial values PASS Wasm-to-Wasm mutable global sharing is live PASS Multiple JavaScript imports return the same WebAssembly module instance PASS v128 globals should work correctly in WebAssembly-to-WebAssembly imports diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any-expected.txt index 0a6c819a77af..9aa83d229ab8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any-expected.txt @@ -1,13 +1,7 @@ -FAIL wasm: reserved import names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Module name, 'test' does not resolve to a valid URL." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") -FAIL wasm-js: reserved import names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Module name, 'test' does not resolve to a valid URL." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") -FAIL wasm: reserved export names should cause WebAssembly.LinkError assert_unreached: Should have rejected: undefined Reached unreachable code -FAIL wasm-js: reserved export names should cause WebAssembly.LinkError assert_unreached: Should have rejected: undefined Reached unreachable code -FAIL wasm-js: reserved module names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Importing a module script failed." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") +PASS wasm: reserved import names should cause WebAssembly.LinkError +PASS wasm-js: reserved import names should cause WebAssembly.LinkError +PASS wasm: reserved export names should cause WebAssembly.LinkError +PASS wasm-js: reserved export names should cause WebAssembly.LinkError +PASS wasm-js: reserved module names should cause WebAssembly.LinkError diff --git a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any.worker-expected.txt index 4a870bad85cb..9aa83d229ab8 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any.worker-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/wasm/jsapi/esm-integration/reserved-import-names.tentative.any.worker-expected.txt @@ -1,13 +1,7 @@ -FAIL wasm: reserved import names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Module name, 'test' does not resolve to a valid URL." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") -FAIL wasm-js: reserved import names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Module name, 'test' does not resolve to a valid URL." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") -FAIL wasm: reserved export names should cause WebAssembly.LinkError assert_unreached: Should have rejected: undefined Reached unreachable code -FAIL wasm-js: reserved export names should cause WebAssembly.LinkError assert_unreached: Should have rejected: undefined Reached unreachable code -FAIL wasm-js: reserved module names should cause WebAssembly.LinkError promise_rejects_js: function "function() { throw e; }" threw object "TypeError: Cross-origin script load denied by Cross-Origin Resource Sharing policy." ("TypeError") expected instance of function "function LinkError() { - [native code] -}" ("LinkError") +PASS wasm: reserved import names should cause WebAssembly.LinkError +PASS wasm-js: reserved import names should cause WebAssembly.LinkError +PASS wasm: reserved export names should cause WebAssembly.LinkError +PASS wasm-js: reserved export names should cause WebAssembly.LinkError +PASS wasm-js: reserved module names should cause WebAssembly.LinkError diff --git a/LayoutTests/ipc/cocoa/videoEncode.html b/LayoutTests/ipc/cocoa/videoEncode.html index c0e81eaba911..2e44a2b1e730 100644 --- a/LayoutTests/ipc/cocoa/videoEncode.html +++ b/LayoutTests/ipc/cocoa/videoEncode.html @@ -22,7 +22,7 @@ id, width, height, startBitrate:62, maxBitrate:91, minBitrate:5, maxFramerate:720916 }); CoreIPC.GPU.LibWebRTCCodecsProxy.EncodeFrame(0, { - id, buffer:{ time: { timeValue:43, timeScale:79, timeFlags:145 }, mirrored:false, rotation:0, colorSpace: {primaries: {optionalValue: 0}, transfer: {optionalValue: 0}, matrix:{optionalValue: 1}, fullRange: {optionalValue: false}}, buffer:{ alias: { variantType:'WebCore::IntSize', variant : { width, height } } }}, timeStamp:61, duration:{}, shouldEncodeAsKeyFrame:true + id, buffer:{ time: { timeValue:43, timeScale:79, timeFlags:145 }, mirrored:false, rotation:0, colorSpace: {primaries: {optionalValue: 0}, transfer: {optionalValue: 0}, matrix:{optionalValue: 1}, fullRange: {optionalValue: false}, chromaLocation: {}}, buffer:{ alias: { variantType:'WebCore::IntSize', variant : { width, height } } }}, timeStamp:61, duration:{}, shouldEncodeAsKeyFrame:true }); CoreIPC.GPU.LibWebRTCCodecsProxy.ReleaseEncoder(0, { id diff --git a/LayoutTests/ipc/coreipc.js b/LayoutTests/ipc/coreipc.js index a15c63ed87c4..e8ca90faac1f 100644 --- a/LayoutTests/ipc/coreipc.js +++ b/LayoutTests/ipc/coreipc.js @@ -245,6 +245,19 @@ const aliases = { 'CGColorSpaceRef': 'WebKit::CoreIPCCGColorSpace' } +// A DestinationColorSpace holding sRGB. Under USE(CG) it is a structured variant; under +// USE(SKIA) sk_sp crosses IPC as the bytes SkColorSpace::serialize() produces, +// which IPC.serializedSRGBColorSpace() obtains from the real serializer. +export function sRGBColorSpace() { + if ('WebKit::CoreIPCCGColorSpace' in CoreIPC.typeInfo) + return { serializableColorSpace: { alias: { optionalValue: { m_cgColorSpace: { alias: { variantType: 'WebCore::ColorSpace', variant: 19 } } } } } }; // WebCore::ColorSpace::SRGB + + if ('sk_sp' in CoreIPC.typeInfo) + return { serializableColorSpace: { alias: { dataReference: IPC.serializedSRGBColorSpace() } } }; + + throw new SerializationError('sRGBColorSpace() supports only the CG and Skia serialization formats'); +} + export function resolveAlias(argumentType) { if (argumentType in aliases) { return resolveAlias(aliases[argumentType]); @@ -584,6 +597,10 @@ export class ArgumentSerializer { case 'UniqueRef': return ArgumentSerializer.serializeArgument({type: innerType, name: argumentDefinition.name}, argument); default: + // A wrapper class such as sk_sp is a template, but the + // generator describes it like any other struct. + if (argumentDefinition.type in CoreIPC.typeInfo) + break; throw new SerializationError(`Don't know how to serialize template '${ templateType }'`); } } diff --git a/LayoutTests/ipc/decode-feConvolveMatrix-kernelSize-overflow.html b/LayoutTests/ipc/decode-feConvolveMatrix-kernelSize-overflow.html index 32e0afc450e8..9805bb7d9a36 100644 --- a/LayoutTests/ipc/decode-feConvolveMatrix-kernelSize-overflow.html +++ b/LayoutTests/ipc/decode-feConvolveMatrix-kernelSize-overflow.html @@ -9,7 +9,7 @@ if (!window.IPC) return testRunner?.notifyDone(); - const { CoreIPC } = await import('./coreipc.js'); + const { CoreIPC, sRGBColorSpace } = await import('./coreipc.js'); const renderingBackendIdentifier = randomIPCID(); o58 = CoreIPC.newStreamConnection(); CoreIPC.GPU.GPUConnectionToWebProcess.CreateRenderingBackend( @@ -33,23 +33,7 @@ k2 : -0.0000015329670121806829, k3 : 8.407790785948902e-44, k4 : -8.633401098587574e-14, - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -57,23 +41,7 @@ subclasses : { variantType : 'WebCore::SourceAlpha', variant : { - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -83,23 +51,7 @@ variant : { floodColor : { data : {} }, floodOpacity : -2.4559581509165345e-24, - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -112,23 +64,7 @@ k2 : -1.175494351e-38, k3 : 1.0369608636003646e-43, k4 : 4.344025239406933e-44, - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -137,23 +73,7 @@ variantType : 'WebCore::FEMerge', variant : { numberOfEffectInputs : 93, - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -161,23 +81,7 @@ subclasses : { variantType : 'WebCore::SourceGraphic', variant : { - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } }, @@ -196,23 +100,7 @@ }, preserveAlpha : false, kernel : [], - operatingColorSpace : { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - } + operatingColorSpace : sRGBColorSpace() } } } diff --git a/LayoutTests/ipc/empty-svgfilterrenderer-expression-crash.html b/LayoutTests/ipc/empty-svgfilterrenderer-expression-crash.html index 3d43984283f8..a6a2d39101e9 100644 --- a/LayoutTests/ipc/empty-svgfilterrenderer-expression-crash.html +++ b/LayoutTests/ipc/empty-svgfilterrenderer-expression-crash.html @@ -7,7 +7,7 @@ window.setTimeout(async () => { if (!window.IPC) return window.testRunner?.notifyDone(); - const { CoreIPC } = await import("./coreipc.js"); + const { CoreIPC, sRGBColorSpace } = await import("./coreipc.js"); const streamConnection = CoreIPC.newStreamConnection(); @@ -27,23 +27,7 @@ renderingMode: 1, renderingPurpose: 0, resolutionScale: 1, - colorSpace: { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: "WebKit::ICCData", - variant: { - data: [], - derivative: 0 - }, - }, - }, - }, - }, - }, - }, + colorSpace: sRGBColorSpace(), bufferFormat: { pixelFormat: 2, useLosslessCompression: 1 }, identifier: 393236, contextIdentifier: 393237, @@ -79,21 +63,7 @@ xChannelSelector: 0, yChannelSelector: 4, scale: 1, - operatingColorSpace: { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: - "WebCore::ColorSpace", - variant: 17, - }, - }, - }, - }, - }, - }, + operatingColorSpace: sRGBColorSpace(), in2IsTainted: false, }, }, diff --git a/LayoutTests/ipc/fecolormatrix-type-values-mismatch-crash.html b/LayoutTests/ipc/fecolormatrix-type-values-mismatch-crash.html index 350734b4228e..cb8c7b96f5b4 100644 --- a/LayoutTests/ipc/fecolormatrix-type-values-mismatch-crash.html +++ b/LayoutTests/ipc/fecolormatrix-type-values-mismatch-crash.html @@ -8,7 +8,7 @@ if (!window.IPC) return window.testRunner?.notifyDone(); - const { CoreIPC } = await import('./coreipc.js'); + const { CoreIPC, sRGBColorSpace } = await import('./coreipc.js'); const streamConnection = CoreIPC.newStreamConnection(); @@ -29,20 +29,7 @@ renderingMode: 1, renderingPurpose: 0, resolutionScale: 10, - colorSpace: { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: 'WebCore::ColorSpace', - variant: 1 - } - } - } - } - } - }, + colorSpace: sRGBColorSpace(), pixelFormat: 1, bufferFormat: { pixelFormat: 1, useLosslessCompression: 0 }, identifier: imageBufferIdentifier, @@ -50,7 +37,7 @@ }); const remoteImageBuffer = streamConnection.newInterface("RemoteImageBuffer", imageBufferIdentifier); - const srgbColorSpace = {serializableColorSpace: {alias: {optionalValue: {m_cgColorSpace: {alias: {variantType: 'WebCore::ColorSpace', variant: 1}}}}}}; + const srgbColorSpace = sRGBColorSpace(); try { remoteImageBuffer.FilteredNativeImage({ diff --git a/LayoutTests/ipc/insufficient-svgfilter-inputs-crash.html b/LayoutTests/ipc/insufficient-svgfilter-inputs-crash.html index 4ca218eb6981..7e3b725d1438 100644 --- a/LayoutTests/ipc/insufficient-svgfilter-inputs-crash.html +++ b/LayoutTests/ipc/insufficient-svgfilter-inputs-crash.html @@ -9,7 +9,7 @@ if (!window.IPC) return window.testRunner?.notifyDone(); - const { CoreIPC } = await import('./coreipc.js'); + const { CoreIPC, sRGBColorSpace } = await import('./coreipc.js'); const streamConnection = CoreIPC.newStreamConnection(); @@ -27,7 +27,7 @@ renderingMode: 0, renderingPurpose: 0, resolutionScale: 1.0, - colorSpace: {serializableColorSpace: {alias: {optionalValue: {m_cgColorSpace: {alias: {variantType: 'WebCore::ColorSpace', variant: 1}}}}}}, + colorSpace: sRGBColorSpace(), bufferFormat: { pixelFormat: 1, useLosslessCompression: 0 }, identifier: imageBufferIdentifier, contextIdentifier: contextIdentifier, @@ -57,7 +57,7 @@ variantType: 'WebCore::FEBlend', variant: { blendMode: 8, - operatingColorSpace: {serializableColorSpace: {alias: {optionalValue: {m_cgColorSpace: {alias: {variantType: 'WebCore::ColorSpace', variant: 1}}}}}} + operatingColorSpace: sRGBColorSpace() } } } diff --git a/LayoutTests/ipc/invalid-feConvolveMatrix-crash.html b/LayoutTests/ipc/invalid-feConvolveMatrix-crash.html index 15c247cb8385..fea956a81976 100644 --- a/LayoutTests/ipc/invalid-feConvolveMatrix-crash.html +++ b/LayoutTests/ipc/invalid-feConvolveMatrix-crash.html @@ -8,7 +8,7 @@ if (!window.IPC) return window.testRunner?.notifyDone(); - const { CoreIPC } = await import('./coreipc.js'); + const { CoreIPC, sRGBColorSpace } = await import('./coreipc.js'); const streamConnection = CoreIPC.newStreamConnection(); @@ -29,20 +29,7 @@ renderingMode: 1, renderingPurpose: 0, resolutionScale: 10, - colorSpace: { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: 'WebCore::ColorSpace', - variant: 1 - } - } - } - } - } - }, + colorSpace: sRGBColorSpace(), pixelFormat: 1, bufferFormat: { pixelFormat: 1, useLosslessCompression: 0 }, identifier: imageBufferIdentifier, @@ -77,20 +64,7 @@ }, preserveAlpha: true, kernel: [], - operatingColorSpace: { - serializableColorSpace: { - alias: { - optionalValue: { - m_cgColorSpace: { - alias: { - variantType: 'WebCore::ColorSpace', - variant: 1 - } - } - } - } - } - } + operatingColorSpace: sRGBColorSpace() } } }], diff --git a/LayoutTests/ipc/invalid-svgfilter-expression-crash.html b/LayoutTests/ipc/invalid-svgfilter-expression-crash.html index 0e0b0747845d..6893db4bc788 100644 --- a/LayoutTests/ipc/invalid-svgfilter-expression-crash.html +++ b/LayoutTests/ipc/invalid-svgfilter-expression-crash.html @@ -9,7 +9,7 @@ if (!window.IPC) return window.testRunner?.notifyDone(); - const { CoreIPC } = await import('./coreipc.js'); + const { CoreIPC, sRGBColorSpace } = await import('./coreipc.js'); const streamConnection = CoreIPC.newStreamConnection(); @@ -27,7 +27,7 @@ renderingMode: 0, renderingPurpose: 0, resolutionScale: 1.0, - colorSpace: {serializableColorSpace: {alias: {optionalValue: {m_cgColorSpace: {alias: {variantType: 'WebCore::ColorSpace', variant: 1}}}}}}, + colorSpace: sRGBColorSpace(), bufferFormat: { pixelFormat: 1, useLosslessCompression: 0 }, identifier: imageBufferIdentifier, contextIdentifier: contextIdentifier @@ -54,7 +54,7 @@ variantType: 'WebCore::FEBlend', variant: { blendMode: 8, - operatingColorSpace: {serializableColorSpace: {alias: {optionalValue: {m_cgColorSpace: {alias: {variantType: 'WebCore::ColorSpace', variant: 1}}}}}} + operatingColorSpace: sRGBColorSpace() } } } diff --git a/LayoutTests/ipc/nested-display-list-draw-control-part-crash.html b/LayoutTests/ipc/nested-display-list-draw-control-part-crash.html index 6c96df22c24d..218c1ebad8a4 100644 --- a/LayoutTests/ipc/nested-display-list-draw-control-part-crash.html +++ b/LayoutTests/ipc/nested-display-list-draw-control-part-crash.html @@ -14,7 +14,7 @@ if (!window.IPC) return; - const { CoreIPC, ArgumentSerializer, StreamConnection } = await import('./coreipc.js'); + const { CoreIPC, ArgumentSerializer, StreamConnection, sRGBColorSpace } = await import('./coreipc.js'); // CoreIPC.js aliases RetainPtr -> CoreIPCCGColorSpace, but the // generated coder wraps it in a leading `bool isEngaged`. Override the field type @@ -73,7 +73,7 @@ renderingMode: 0, renderingPurpose: 0, resolutionScale: 1.0, - colorSpace: { serializableColorSpace: { alias: { optionalValue: { m_cgColorSpace: { alias: { variantType: 'WebCore::ColorSpace', variant: 19 } } } } } }, + colorSpace: sRGBColorSpace(), bufferFormat: { pixelFormat: 2, useLosslessCompression: 1 }, identifier: imageBufferIdentifier, contextIdentifier: graphicsContextIdentifier diff --git a/LayoutTests/ipc/restore-empty-stack-crash.html b/LayoutTests/ipc/restore-empty-stack-crash.html index fb45edf7dd37..14402eb7d45c 100644 --- a/LayoutTests/ipc/restore-empty-stack-crash.html +++ b/LayoutTests/ipc/restore-empty-stack-crash.html @@ -4,12 +4,12 @@ window.testRunner?.waitUntilDone(); if (window.IPC) { import('./coreipc.js').then(({ - CoreIPC + CoreIPC, sRGBColorSpace }) => { o10=CoreIPC.newStreamConnection(); CoreIPC.GPU.GPUConnectionToWebProcess.CreateRenderingBackend(0,{renderingBackendIdentifier:393219,connectionHandle:o10}); o12=o10.newInterface("RemoteRenderingBackend", 393219); - o12.CreateImageBuffer({logicalSize:{width:32,height:18},renderingMode:3,renderingPurpose:1,resolutionScale:489626271805,colorSpace:{serializableColorSpace:{alias:{optionalValue:{m_cgColorSpace:{alias:{variantType:'WebCore::ColorSpace',variant:5}}}}}},pixelFormat:1,bufferFormat:{pixelFormat:1,useLosslessCompression:0},identifier:393225,contextIdentifier:393226}); + o12.CreateImageBuffer({logicalSize:{width:32,height:18},renderingMode:3,renderingPurpose:1,resolutionScale:489626271805,colorSpace:sRGBColorSpace(),pixelFormat:1,bufferFormat:{pixelFormat:1,useLosslessCompression:0},identifier:393225,contextIdentifier:393226}); o10.connection.waitForMessage(393225, IPC.messages.RemoteImageBufferProxy_DidCreateBackend.name, 1); o31=o10.newInterface("RemoteGraphicsContext", 393226); o31.Restore({}); diff --git a/LayoutTests/ipc/serialized-type-info.html b/LayoutTests/ipc/serialized-type-info.html index 5aa1204e40c7..17800540109f 100644 --- a/LayoutTests/ipc/serialized-type-info.html +++ b/LayoutTests/ipc/serialized-type-info.html @@ -188,6 +188,9 @@ result.push("WKDDActionContext"); } } + } else { + result.push("UnixFileDescriptor"); + result.push("GTlsCertificateFlags"); } } return result.sort(); diff --git a/LayoutTests/platform/glib/TestExpectations b/LayoutTests/platform/glib/TestExpectations index c8cde2869f6f..5804233c239b 100644 --- a/LayoutTests/platform/glib/TestExpectations +++ b/LayoutTests/platform/glib/TestExpectations @@ -428,7 +428,7 @@ imported/w3c/web-platform-tests/css/css-transforms/transform3d-preserve3d-013.ht imported/w3c/web-platform-tests/css/css-transforms/transforms-skewY.html [ Pass ] imported/w3c/web-platform-tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-new.html [ Pass ] imported/w3c/web-platform-tests/css/selectors/selectors-4/lang-020.html [ Pass ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html [ Pass ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-028.html [ Pass ] # css-values passing for us. imported/w3c/web-platform-tests/css/css-values/ch-unit-003.html [ Pass ] @@ -1250,9 +1250,6 @@ accessibility/statictext-path.html [ Failure ] # aria-braille* attributes are not implemented: webkit.org/b/220719 accessibility/braille-label-role.html [ Failure ] -# Key events for AX actions seems to not be not being emitted -webkit.org/b/221022 accessibility/keyevents-for-actions-mimic-real-key-events.html [ Timeout ] - # Test requires WebKitTestRunner property 'standaloneWebApplicationURL', which is only implemented for Cocoa platforms. http/tests/resourceLoadStatistics/standalone-web-application-exempt-from-website-data-deletion.html [ Skip ] @@ -1898,7 +1895,7 @@ webkit.org/b/224767 imported/w3c/web-platform-tests/media-source/mediasource-cha # See also bug #175578. webkit.org/b/167108 imported/w3c/web-platform-tests/media-source/mediasource-avtracks.html [ Failure ] -webkit.org/b/167108 imported/w3c/web-platform-tests/media-source/mediasource-duration.html [ Failure ] +webkit.org/b/167108 imported/w3c/web-platform-tests/media-source/mediasource-duration.html [ Failure Pass ] webkit.org/b/210486 imported/w3c/web-platform-tests/media-source/mediasource-correct-frames-after-reappend.html [ Failure ] @@ -2115,11 +2112,6 @@ http/tests/push-api [ Skip ] webkit.org/b/202750 http/tests/download/anchor-download-attribute-content-disposition-no-extension-text-plain.html [ Failure ] -# libsoup 3.6.6 mangles interior spaces in Content-Disposition filenames to '_' -# (regressed by libsoup 9e1570c9, fixed upstream by db09564e). Remove once the -# SDK ships a libsoup with that fix. -http/tests/download/basic-ascii.html [ Failure ] - # There is no network load scheduling or prioritization with NetworkProcess. webkit.org/b/123431 http/tests/local/link-stylesheet-load-order-preload.html [ Failure ] webkit.org/b/123431 http/tests/local/link-stylesheet-load-order.html [ Failure ] @@ -2848,7 +2840,7 @@ imported/w3c/web-platform-tests/webrtc-extensions/transfer-datachannel-service-w imported/w3c/web-platform-tests/webrtc/simulcast/setParameters-maxFramerate.https.html [ Skip ] # Timeout imported/w3c/web-platform-tests/webrtc/simulcast/vp9-scalability-mode.https.html [ Skip ] # Timeout webrtc/getDisplayMedia-odd-size.html [ Skip ] # Timeout -webrtc/video-rotation.html [ Failure ] +webkit.org/b/322821 webrtc/video-rotation.html [ Failure Pass Timeout ] webrtc/video-maxBitrate-vp8.html [ Skip ] # Timeout webrtc/video-maxBitrate.html [ Skip ] # Timeout @@ -2961,7 +2953,7 @@ imported/w3c/web-platform-tests/webrtc-encoded-transform/tentative/RTCEncodedFra http/wpt/webrtc/video-script-transform-simulcast.html [ Skip ] # This test is a constant failure (assert_true: front stream should be small expected true got false). -webkit.org/b/313153 webrtc/video-replace-track.html [ Failure ] +webkit.org/b/313153 webrtc/video-replace-track.html [ Failure Timeout ] # GStreamerRtpSenderBackend::setMediaStreamIds() unimplemented. webkit.org/b/235885 webrtc/video.html [ Skip ] @@ -2999,7 +2991,6 @@ webkit.org/b/235885 webrtc/canvas-to-peer-connection-vp8.html [ Failure ] imported/w3c/web-platform-tests/webrtc/RTCDataChannel-worker-GC.html [ Skip ] # Timeout imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-remote-track-currentTime.https.html [ Failure ] imported/w3c/web-platform-tests/webrtc/RTCRtpReceiver-track-settings.tentative.html [ Failure ] -imported/w3c/web-platform-tests/webrtc/rtp-stats-lifetime.https.html?interop-2026 [ Failure ] # The last promise test here fails because webrtcbin doesn't rely on a singleton signaling thread. # See also comments in: @@ -3161,10 +3152,12 @@ imported/w3c/web-platform-tests/html/semantics/forms/the-meter-element/meter-app imported/w3c/web-platform-tests/html/semantics/forms/the-meter-element/meter-appearance-none-suboptimum-value-rendering.html [ ImageOnlyFailure ] # Passes for GTK/WPE (but not for Mac/iOS) after WPT update of css-writing-modes tests +webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-001.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-004.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-006.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-008.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-009.html [ Pass ] +webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-012.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-015.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-016.html [ Pass ] webkit.org/b/214291 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-018.html [ Pass ] @@ -3219,9 +3212,6 @@ imported/w3c/web-platform-tests/css/css-images/infinite-radial-gradient-refcrash webkit.org/b/203448 imported/w3c/web-platform-tests/css/css-position/position-absolute-dynamic-static-position-table-cell.html [ Pass ] -webkit.org/b/209080 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-001.html [ Pass ] -webkit.org/b/209080 imported/w3c/web-platform-tests/css/css-writing-modes/available-size-012.html [ Pass ] - webkit.org/b/215799 imported/w3c/web-platform-tests/css/css-content/quotes-005.html [ ImageOnlyFailure ] # WIRELESS_PLAYBACK_TARGET not enabled. @@ -3406,19 +3396,16 @@ http/tests/ipc/webpageproxy-didfailload-failingurl-message-check.html [ Skip ] # CertificateInfo serializes a GRefPtr that coreipc.js cannot construct. http/tests/ipc/createnewpage-file-body-sandbox-extension.html [ Skip ] -# Generic regressions whose IPC payload needs porting to Skia's colorspace format. -ipc/nested-display-list-draw-control-part-crash.html [ Skip ] -ipc/move-to-image-buffer-cross-thread-font-crash.html [ Skip ] +# RemoteRenderingBackend::PrepareImageBufferSetsForDisplay is PLATFORM(COCOA). ipc/remotedisplaylistrecorder-drawcontrolpart-slidertrackpart-crash.html [ Skip ] -ipc/decode-feConvolveMatrix-kernelSize-overflow.html [ Skip ] -ipc/fecolormatrix-type-values-mismatch-crash.html [ Skip ] -ipc/insufficient-svgfilter-inputs-crash.html [ Skip ] -ipc/invalid-feConvolveMatrix-crash.html [ Skip ] -ipc/invalid-svgfilter-expression-crash.html [ Skip ] ipc/mark-surfaces-volatile-during-prepare-for-display.html [ Skip ] -ipc/restore-empty-stack-crash.html [ Skip ] + +# Hardcodes Cocoa's WebCore::FontPlatformDataAttributes in the IPC payload. +ipc/move-to-image-buffer-cross-thread-font-crash.html [ Skip ] + +# Sends WebCore::PixelFormat index 3; the glib ports enable none of RGB10, RGB10A8 +# and RGBA16F, so the enum stops at BGRA8. ipc/convert-to-luminance-mask-float16.html [ Skip ] -ipc/empty-svgfilterrenderer-expression-crash.html [ Skip ] # ATTACHMENT_ELEMENT is disabled in glib ports. ipc/restrictedendpoints/allow-access-attachmentElement.html [ Skip ] @@ -4006,8 +3993,6 @@ webkit.org/b/297178 media/media-source/media-source-paint-stereo-to-canvas.html # Flaky failure webkit.org/b/175419 imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https.html [ Pass Failure ] -# This test fails both invalid-chunked-encoding cases -webkit.org/b/175419 imported/w3c/web-platform-tests/service-workers/service-worker/registration-script.https.html [ Failure ] # This test requires the ServiceWorkerRegistration.showNotification webkit.org/b/175419 http/tests/workers/service/openwindow-from-notification-click.html [ Skip ] @@ -4047,8 +4032,6 @@ webkit.org/b/199001 accessibility/set-selected-text-range-after-newline.html [ F imported/w3c/web-platform-tests/websockets/keeping-connection-open/001.html?wss [ Slow ] # Issues with WebSockets, many due to macOS/iOS and "glib" dealing with console messages differently -webkit.org/b/206652 imported/w3c/web-platform-tests/websockets/constructor/011.html?default [ Failure ] -webkit.org/b/206652 imported/w3c/web-platform-tests/websockets/constructor/011.html?wss [ Failure ] webkit.org/b/252878 imported/w3c/web-platform-tests/websockets/multi-globals/message-received.html?wss [ Failure Pass ] webkit.org/b/252878 imported/w3c/web-platform-tests/websockets/unload-a-document/003.html?wss [ Failure Pass ] webkit.org/b/252878 imported/w3c/web-platform-tests/websockets/unload-a-document/004.html?wss [ Failure Pass ] @@ -4065,9 +4048,6 @@ webkit.org/b/201981 http/wpt/resource-timing/rt-resources-per-worker.html [ Fail webkit.org/b/306019 imported/w3c/web-platform-tests/resource-timing/resource_timing.worker.html [ Failure Pass ] -# ch units should be ignored in these tests. -webkit.org/b/206001 imported/w3c/web-platform-tests/css/css-values/ch-unit-017.html [ ImageOnlyFailure ] - # WPT fetch tests. webkit.org/b/206416 imported/w3c/web-platform-tests/fetch/range/sw.https.window.html [ Failure ] @@ -4076,19 +4056,6 @@ imported/w3c/web-platform-tests/fetch/content-encoding/gzip/bad-gzip-body.any.ht imported/w3c/web-platform-tests/fetch/content-encoding/gzip/bad-gzip-body.any.serviceworker.html [ Failure ] imported/w3c/web-platform-tests/fetch/content-encoding/gzip/bad-gzip-body.any.sharedworker.html [ Failure ] imported/w3c/web-platform-tests/fetch/content-encoding/gzip/bad-gzip-body.any.worker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.serviceworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.sharedworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.worker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/big-zstd-body.https.any.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/big-zstd-body.https.any.serviceworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/big-zstd-body.https.any.sharedworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/big-zstd-body.https.any.worker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/zstd-body.https.any.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/zstd-body.https.any.serviceworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/zstd-body.https.any.sharedworker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/zstd-body.https.any.worker.html [ Failure ] -imported/w3c/web-platform-tests/fetch/content-encoding/zstd/zstd-navigation.https.window.html [ Failure ] imported/w3c/web-platform-tests/fetch/content-length/too-long.window.html [ Failure ] imported/w3c/web-platform-tests/fetch/content-type/response.window.html [ Failure ] imported/w3c/web-platform-tests/fetch/http-cache/partial.any.html [ Failure ] @@ -4358,6 +4325,7 @@ imported/w3c/web-platform-tests/css/css-scroll-snap/input/mouse-wheel.html [ Ski imported/w3c/web-platform-tests/css/css-scroll-snap/snap-at-user-scroll-end.html [ Skip ] imported/w3c/web-platform-tests/css/css-transforms/scroll-preserve-3d.html [ Skip ] imported/w3c/web-platform-tests/dom/events/non-cancelable-when-passive [ Skip ] +imported/w3c/web-platform-tests/html/semantics/popovers/popover-focus-invoker-inside-popover.html [ Skip ] imported/w3c/web-platform-tests/html/semantics/popovers/popover-light-dismiss-scroll-within.html [ Skip ] imported/w3c/web-platform-tests/html/semantics/popovers/popover-self-invoke.html [ Skip ] imported/w3c/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling.html [ Skip ] @@ -5224,7 +5192,6 @@ imported/w3c/web-platform-tests/webcodecs/videoFrame-copyTo.crossOriginIsolated. imported/w3c/web-platform-tests/workers/Worker-creation-happens-in-parallel.https.html [ Skip ] imported/w3c/web-platform-tests/workers/postMessage_block.https.html [ Skip ] imported/w3c/web-platform-tests/workers/Worker-postMessage-happens-in-parallel.https.html [ Skip ] -ipc/serialized-type-info.html [ Skip ] ipc/stream-sync-reply-shared-memory.html [ Skip ] webkit.org/b/297737 ipc/send-gradient.html [ Skip ] webkit.org/b/297737 ipc/send-filter.html [ Skip ] @@ -5305,13 +5272,15 @@ webkit.org/b/319045 [ Debug ] accessibility/button-in-deep-dom.html [ Timeout ] webkit.org/b/319047 [ Debug ] imported/w3c/web-platform-tests/css/css-overflow/line-clamp/line-clamp-033.html [ Crash ] webkit.org/b/319049 [ Debug ] http/tests/cache/cancel-multiple-post-xhrs.html [ Pass Failure ] webkit.org/b/319050 [ Debug ] imported/w3c/web-platform-tests/fetch/local-network-access/iframe.tentative.https.window.html [ Failure ] -webkit.org/b/319051 [ Debug ] imported/w3c/web-platform-tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html [ Failure ] +webkit.org/b/319051 [ Debug ] imported/w3c/web-platform-tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html [ Failure Pass ] webkit.org/b/319052 [ Debug ] http/tests/websocket/tests/hybi/inspector/handshake-error.html [ Pass Failure ] webkit.org/b/319053 [ Debug ] media/video-playback-restriction-play-before-load.html [ Failure ] webkit.org/b/319310 [ Debug ] fast/repaint/iframe-avoid-redundant-repaint.html [ Failure Pass ] webkit.org/b/319311 [ Debug ] fast/repaint/missing-out-of-flow-repaint-on-destroy.html [ Pass ImageOnlyFailure ] webkit.org/b/319312 [ Debug ] workers/bomb.html [ Skip ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-string-023.html [ ImageOnlyFailure ] + webkit.org/b/319950 imported/w3c/web-platform-tests/css/css-pseudo/marker-hit-testing.html [ Failure ] # WebTransport is Cocoa-only (non-Cocoa ports are a stub). https://bugs.webkit.org/show_bug.cgi?id=319008 @@ -5400,6 +5369,10 @@ webkit.org/b/322641 [ Debug ] imported/w3c/web-platform-tests/web-animations/tim webkit.org/b/322642 [ Debug ] imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-unconnected-outputs.https.window.html [ Pass Failure ] webkit.org/b/322646 [ Debug ] media/track/track-readiness-state.html [ Pass Failure ] +webkit.org/b/322814 imported/w3c/web-platform-tests/mediacapture-record/MediaRecorder-error.html [ Crash Failure Pass ] +webkit.org/b/322815 imported/w3c/web-platform-tests/mediacapture-record/MediaRecorder-pause-resume.html [ Pass Timeout ] +webkit.org/b/322816 imported/w3c/web-platform-tests/resource-timing/initiator-type/style.html [ Failure Pass ] + # End: Common failures between GTK and WPE. #//////////////////////////////////////////////////////////////////////////////////////// diff --git a/LayoutTests/platform/gtk/TestExpectations b/LayoutTests/platform/gtk/TestExpectations index 257a1131d315..b44ff7efa928 100644 --- a/LayoutTests/platform/gtk/TestExpectations +++ b/LayoutTests/platform/gtk/TestExpectations @@ -24,7 +24,6 @@ fast/scrolling/gtk [ Pass ] swipe [ Pass ] webkit.org/b/254521 [ Release ] imported/w3c/web-platform-tests/media-source/mediasource-getvideoplaybackquality.html [ Pass Failure ] -webkit.org/b/277912 imported/w3c/web-platform-tests/css/css-borders/corner-shape/corner-shape-backdrop-filter-overflow.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/CSS2/linebox/vertical-align-baseline-009.xht [ Pass ] imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-to-sticky-003.html [ Pass ] imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-to-sticky-004.html [ Pass ] @@ -1262,9 +1261,9 @@ webkit.org/b/319058 [ Debug ] media/media-h264-webm-error.html [ Failure ] webkit.org/b/319059 [ Debug ] media/vp9.html [ Failure ] webkit.org/b/319060 [ Debug ] media/auto-play-video-in-about-blank-iframe.html [ Failure ] webkit.org/b/319061 [ Debug ] media/muted-video-is-playing-audio.html [ Timeout ] -webkit.org/b/319062 [ Debug ] inspector/dom/getMediaStats.html [ Failure ] +webkit.org/b/319062 [ Debug ] inspector/dom/getMediaStats.html [ Failure Pass ] webkit.org/b/319063 [ Debug ] fullscreen/full-screen-enter-while-exiting.html [ Timeout ] -webkit.org/b/319064 [ Debug ] fullscreen/video-inside-flex-item.html [ Failure ] +webkit.org/b/319064 [ Debug ] fullscreen/video-inside-flex-item.html [ Failure Pass ] webkit.org/b/319066 [ Debug ] imported/w3c/web-platform-tests/css/css-view-transitions/view-transition-waituntil-finished-promise.html [ Failure ] webkit.org/b/319072 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-audio-element/audio-loading-lazy-window-onload.html [ Failure Pass ] @@ -1323,3 +1322,8 @@ webkit.org/b/322648 [ Debug ] navigation-api/navigation-api-rate-limit-history-a webkit.org/b/322650 [ Debug ] webrtc/video-h264.html [ Pass Failure ] webkit.org/b/322651 [ Debug ] webrtc/video-remote-mute.html [ Pass Failure ] webkit.org/b/322652 [ Debug ] workers/btoa-oom.html [ Pass Timeout ] +webkit.org/b/322811 [ Debug ] fast/mediastream/applyConstraints-with-takePhoto.html [ Pass Timeout ] +webkit.org/b/322818 [ Debug ] imported/w3c/web-platform-tests/wasm/core/simd/simd_f32x4_cmp.wast.js.html [ Pass Timeout ] +webkit.org/b/322819 [ Debug ] imported/w3c/web-platform-tests/wasm/core/simd/simd_f64x2_cmp.wast.js.html [ Pass Timeout ] +webkit.org/b/319070 [ Debug ] imported/w3c/web-platform-tests/wasm/core/simd/simd_f32x4_rounding.wast.js.html [ Pass Timeout ] +webkit.org/b/322820 [ Release ] media/video-seek-past-end-paused.html [ Failure Pass ] diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations index 66b591edb373..f2a46d8ff060 100644 --- a/LayoutTests/platform/ios/TestExpectations +++ b/LayoutTests/platform/ios/TestExpectations @@ -207,7 +207,9 @@ imported/w3c/web-platform-tests/payment-request/payment-request-disallowed-when- imported/w3c/web-platform-tests/html/rendering/non-replaced-elements/form-controls/text-transform.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/html/rendering/non-replaced-elements/phrasing-content-0/br-wbr-content/content-property.tentative.html [ ImageOnlyFailure ] -webkit.org/b/259089 imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html [ ImageOnlyFailure ] +webkit.org/b/259089 imported/w3c/web-platform-tests/css/css-overflow/text-overflow-028.html [ ImageOnlyFailure ] + +imported/w3c/web-platform-tests/css/css-overflow/before-after-pseudo-element-scrolling.html [ ImageOnlyFailure ] webkit.org/b/279302 imported/w3c/web-platform-tests/css/css-ui/outline-width-rounding.tentative.html [ Failure ] webkit.org/b/279302 imported/w3c/web-platform-tests/css/css-ui/parsing/outline-width-computed.html [ Failure ] @@ -280,6 +282,9 @@ fast/images/jpegxl-with-color-profile.html [ Pass ] # Video as an image source is only supported on macOS and iOS. fast/images/video-as-image.html [ Pass ] +# ImageIO rejects an acTL declaring zero frames, so the default image never decodes. +fast/images/apng-acTL-zero-frame-count.html [ Skip ] + # No fullscreen API on iOS fullscreen http/tests/fullscreen @@ -7356,10 +7361,10 @@ imported/w3c/web-platform-tests/css/css-text/white-space/pre-wrap-leading-spaces imported/w3c/web-platform-tests/css/css-text/white-space/pre-wrap-leading-spaces-013.html [ Pass ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet.html [ Pass ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-ui/outline-028.html [ Pass ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-010.html [ Pass ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-011.html [ Pass ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-013.html [ Pass ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-014.html [ Pass ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-010.html [ Pass ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-011.html [ Pass ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-013.html [ Pass ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-014.html [ Pass ImageOnlyFailure ] fast/forms/textfield-outline.html [ Pass Failure ] http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html [ Pass Failure ] http/tests/security/clipboard/copy-paste-html-across-origin-strips-mso-list.html [ Pass Failure ] @@ -10139,10 +10144,10 @@ imported/w3c/web-platform-tests/svg/animations/reinserting-svg-into-document.htm imported/w3c/web-platform-tests/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch.html [ Pass Failure ] # rdar://178676720 -imported/w3c/web-platform-tests/css/css-ui/text-overflow-001.html [ Pass ImageOnlyFailure ] # rdar://178676888 -imported/w3c/web-platform-tests/css/css-ui/text-overflow-002.html [ Pass ImageOnlyFailure ] # rdar://178676888 -imported/w3c/web-platform-tests/css/css-ui/text-overflow-004.html [ Pass ImageOnlyFailure ] # rdar://178676888 -imported/w3c/web-platform-tests/css/css-ui/text-overflow-003.html [ Pass ImageOnlyFailure ] # rdar://178676888 +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-001.html [ Pass ImageOnlyFailure ] # rdar://178676888 +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-002.html [ Pass ImageOnlyFailure ] # rdar://178676888 +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-004.html [ Pass ImageOnlyFailure ] # rdar://178676888 +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-003.html [ Pass ImageOnlyFailure ] # rdar://178676888 imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-iframe.html [ Pass ImageOnlyFailure ] # rdar://178676913 imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/modal-dialog-generated-content.html [ Pass ImageOnlyFailure ] # rdar://178676913 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/coords-viewattr-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/coords-viewattr-01-b-expected.txt index d0c3cf2cd29f..e93786598c2b 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/coords-viewattr-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/coords-viewattr-01-b-expected.txt @@ -48,7 +48,7 @@ layer at (0,-27.75) size 112x58 backgroundClip at (0,0) size 480x360 clip at (0, layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.75) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (120,80) size 50x30 clip at (120,80) size 50x30 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -60,10 +60,10 @@ layer at (0,-12.75) size 50x43 backgroundClip at (0,0) size 480x360 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 25x10 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 24.00: "xMid*" RenderSVGRect {rect} at (0.50,13.25) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 48.34x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.75) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (189.98,80) size 50.02x30 clip at (189.98,80) size 50.02x30 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -75,10 +75,10 @@ layer at (0,-12.75) size 50x43 backgroundClip at (0,0) size 480x360 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 26x10 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 25.50: "xMax*" RenderSVGRect {rect} at (0.50,13.25) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 30.02x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.75) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (119.98,130) size 50.02x30 clip at (119.98,130) size 50.02x30 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -94,10 +94,10 @@ layer at (0,-27.75) size 124x88 backgroundClip at (0,0) size 480x360 clip at (0, RenderSVGInlineText {#text} at (0,0) size 27x10 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMin" RenderSVGRect {rect} at (0.50,13.25) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x60 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.75) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (300,80) size 30x60 clip at (300,80) size 30x60 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -109,10 +109,10 @@ layer at (0,-12.75) size 30x73 backgroundClip at (0,0) size 480x360 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 27x10 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMid" RenderSVGRect {rect} at (0.50,13.25) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.75) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (350,80) size 30x60 clip at (350,80) size 30x60 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -124,10 +124,10 @@ layer at (0,-12.75) size 30x73 backgroundClip at (0,0) size 480x360 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 28x10 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 27.50: "*YMax" RenderSVGRect {rect} at (0.50,13.25) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.75) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (400,80) size 30x60 clip at (400,80) size 30x60 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.txt index 2da0055fa2f5..0c07f7048da8 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.txt @@ -40,11 +40,11 @@ layer at (0,0) size 450x300 backgroundClip at (0.50,0.50) size 479.50x359.50 RenderSVGText {text} at (9,348) size 586x38 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 586x37 chunk 1 text run 1 at (10.00,380.00) startOffset 0 endOffset 34 width 585.21: "type: gamma ampl:2 exponents:5/3/1" -layer at (10,10) size 580x40 backgroundClip at (15,5) size 450x300 clip at (15,5) size 450x300 +layer at (10,10) size 580x40 backgroundClip at (0,0) size 480x360 clip at (0,0) size 480x360 RenderSVGRect {rect} at (9,9) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=10.00] [y=10.00] [width=580.00] [height=40.00] -layer at (10,110) size 580x40 backgroundClip at (15,5) size 450x300 clip at (15,5) size 450x300 +layer at (10,110) size 580x40 backgroundClip at (0,0) size 480x360 clip at (0,0) size 480x360 RenderSVGRect {rect} at (9,109) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=10.00] [y=110.00] [width=580.00] [height=40.00] -layer at (10,210) size 580x40 backgroundClip at (15,5) size 450x300 clip at (15,5) size 450x300 +layer at (10,210) size 580x40 backgroundClip at (0,0) size 480x360 clip at (0,0) size 480x360 RenderSVGRect {rect} at (9,209) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=10.00] [y=210.00] [width=580.00] [height=40.00] -layer at (10,310) size 580x40 backgroundClip at (15,5) size 450x300 clip at (15,5) size 450x300 +layer at (10,310) size 580x40 backgroundClip at (0,0) size 480x360 clip at (0,0) size 480x360 RenderSVGRect {rect} at (9,309) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=10.00] [y=310.00] [width=580.00] [height=40.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-example-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-example-01-b-expected.txt index cb96b43067bc..1fa986e85da7 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-example-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/filters-example-01-b-expected.txt @@ -9,7 +9,7 @@ layer at (0,0) size 480x360 RenderSVGInlineText {#text} at (0,0) size 264x46 chunk 1 text run 1 at (10.00,340.00) startOffset 0 endOffset 16 width 263.34: "$Revision: 1.7 $" RenderSVGRect {rect} at (1,1) size 478x358 [stroke={[type=SOLID] [color=#000000]}] [x=1.00] [y=1.00] [width=478.00] [height=358.00] -layer at (0,0) size 300x180 clip at (0,0) size 200x120 +layer at (0,0) size 300x180 RenderSVGViewportContainer {svg} at (0,0) size 300x180 RenderSVGHiddenContainer {defs} at (0,0) size 0x0 RenderSVGHiddenContainer {filter} at (0,0) size 0x0 @@ -17,7 +17,7 @@ layer at (0,0) size 300x180 clip at (0,0) size 200x120 RenderSVGHiddenContainer {feOffset} at (0,0) size 0x0 RenderSVGHiddenContainer {feComposite} at (0,0) size 0x0 RenderSVGRect {rect} at (1,1) size 198x118 [stroke={[type=SOLID] [color=#0000FF]}] [fill={[type=SOLID] [color=#888888]}] [x=1.00] [y=1.00] [width=198.00] [height=118.00] -layer at (12.50,30) size 176x60 backgroundClip at (80,110) size 300x180 clip at (80,110) size 300x180 +layer at (12.50,30) size 176x60 RenderSVGTransformableContainer {g} at (12.50,30) size 175x60 RenderSVGTransformableContainer {g} at (0,0) size 175x60 RenderSVGPath {path} at (0,0) size 175x60 [stroke={[type=SOLID] [color=#D90000] [stroke width=10.00]}] [data="M 50 90 C 0 90 0 30 50 30 L 150 30 C 200 30 200 90 150 90 Z"] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/painting-marker-03-f-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/painting-marker-03-f-expected.png new file mode 100644 index 000000000000..37d532da1de4 Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/painting-marker-03-f-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/types-basicDOM-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/types-basicDOM-01-b-expected.txt index 824b18fdc2a0..93b658505912 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/types-basicDOM-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/W3C-SVG-1.1/types-basicDOM-01-b-expected.txt @@ -27,6 +27,6 @@ layer at (0,0) size 402x155 RenderSVGText {text} at (100,111) size 302x24 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 302x23 chunk 1 text run 1 at (100.00,130.00) startOffset 0 endOffset 35 width 301.10: "Some other text with id 'otherText'" -layer at (0,0) size 110x110 backgroundClip at (0,0) size 50x50 clip at (0,0) size 55x55 +layer at (0,0) size 110x110 backgroundClip at (0,0) size 50x50 RenderSVGViewportContainer {svg} at (0,0) size 110x110 RenderSVGEllipse {circle} at (-50,-50) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=0.00] [cy=0.00] [r=50.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.png new file mode 100644 index 000000000000..fe5bc5bdd9d5 Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.txt index 7a4581c5a0cb..568b36a07943 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/container-opacity-clip-viewBox-expected.txt @@ -7,7 +7,7 @@ layer at (0,0) size 800x600 RenderSVGViewportContainer {svg} at (0,0) size 800x600 [opacity=0.90] layer at (0,0) size 200x200 RenderSVGTransformableContainer {g} at (0,0) size 200x200 -layer at (0,0) size 200x200 backgroundClip at (0,0) size 83x64 clip at (0,0) size 117x116 +layer at (0,0) size 200x200 backgroundClip at (0,0) size 83x64 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGRect {rect} at (-83,-84) size 166x148 [fill={[type=SOLID] [color=#008000]}] [x=-83.00] [y=-84.00] [width=166.00] [height=148.00] layer at (0,-14) size 368x48 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Discrete-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Discrete-expected.txt index b3fa4551bb70..1aabad4db15a 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Discrete-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Discrete-expected.txt @@ -34,11 +34,11 @@ layer at (0,0) size 450x300 backgroundClip at (0.50,0.50) size 649x419 RenderSVGText {text} at (19,353) size 567x20 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 567x19 chunk 1 text run 1 at (20.00,370.00) startOffset 0 endOffset 75 width 566.84: "type: discrete [0.0 0.25 0.5 0.75 1] -- Result should be quantized gradient" -layer at (20,10) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,10) size 580x40 RenderSVGRect {rect} at (19,9) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=10.00] [width=580.00] [height=40.00] -layer at (20,110) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,110) size 580x40 RenderSVGRect {rect} at (19,109) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=110.00] [width=580.00] [height=40.00] -layer at (20,210) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,210) size 580x40 RenderSVGRect {rect} at (19,209) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=210.00] [width=580.00] [height=40.00] -layer at (20,310) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,310) size 580x40 RenderSVGRect {rect} at (19,309) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=310.00] [width=580.00] [height=40.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Gamma-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Gamma-expected.txt index fdb5e3bd549c..d303dafa7249 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Gamma-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Gamma-expected.txt @@ -40,11 +40,11 @@ layer at (0,0) size 450x300 backgroundClip at (0.50,0.50) size 649x419 RenderSVGText {text} at (19,373) size 93x20 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 93x19 chunk 1 text run 1 at (20.00,390.00) startOffset 0 endOffset 12 width 92.17: "the gradient" -layer at (20,10) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,10) size 580x40 RenderSVGRect {rect} at (19,9) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=10.00] [width=580.00] [height=40.00] -layer at (20,110) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,110) size 580x40 RenderSVGRect {rect} at (19,109) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=110.00] [width=580.00] [height=40.00] -layer at (20,210) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,210) size 580x40 RenderSVGRect {rect} at (19,209) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=210.00] [width=580.00] [height=40.00] -layer at (20,310) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,310) size 580x40 RenderSVGRect {rect} at (19,309) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=310.00] [width=580.00] [height=40.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Linear-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Linear-expected.txt index 5b4f552f71a8..57545bb6de24 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Linear-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Linear-expected.txt @@ -34,11 +34,11 @@ layer at (0,0) size 450x300 backgroundClip at (0.50,0.50) size 649x419 RenderSVGText {text} at (19,353) size 606x20 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 606x19 chunk 1 text run 1 at (20.00,370.00) startOffset 0 endOffset 79 width 605.80: "type: linear slope=0.5 intercept=0.25 -- Result should be less extreme gradient" -layer at (20,10) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,10) size 580x40 RenderSVGRect {rect} at (19,9) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=10.00] [width=580.00] [height=40.00] -layer at (20,110) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,110) size 580x40 RenderSVGRect {rect} at (19,109) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=110.00] [width=580.00] [height=40.00] -layer at (20,210) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,210) size 580x40 RenderSVGRect {rect} at (19,209) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=210.00] [width=580.00] [height=40.00] -layer at (20,310) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,310) size 580x40 RenderSVGRect {rect} at (19,309) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=310.00] [width=580.00] [height=40.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Table-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Table-expected.txt index b2f83ff6cbb2..d1af3d75eb43 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Table-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/feComponentTransfer-Table-expected.txt @@ -34,11 +34,11 @@ layer at (0,0) size 450x300 backgroundClip at (0.50,0.50) size 649x419 RenderSVGText {text} at (19,353) size 468x20 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 468x19 chunk 1 text run 1 at (20.00,370.00) startOffset 0 endOffset 61 width 467.60: "type: table [0 0 1 1] -- Result should be compressed gradient" -layer at (20,10) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,10) size 580x40 RenderSVGRect {rect} at (19,9) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=10.00] [width=580.00] [height=40.00] -layer at (20,110) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,110) size 580x40 RenderSVGRect {rect} at (19,109) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=110.00] [width=580.00] [height=40.00] -layer at (20,210) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,210) size 580x40 RenderSVGRect {rect} at (19,209) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=210.00] [width=580.00] [height=40.00] -layer at (20,310) size 580x40 backgroundClip at (25,8.31) size 750x500 clip at (25,8.31) size 750x500 +layer at (20,310) size 580x40 RenderSVGRect {rect} at (19,309) size 580x40 [fill={[type=SOLID] [color=#00000000]}] [x=20.00] [y=310.00] [width=580.00] [height=40.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-and-object-creation-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-and-object-creation-expected.png new file mode 100644 index 000000000000..fd8f12fe416f Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-and-object-creation-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-creation-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-creation-expected.png new file mode 100644 index 000000000000..fd8f12fe416f Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/js-late-marker-creation-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/marker-default-width-height-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/marker-default-width-height-expected.png new file mode 100644 index 000000000000..f33b1a752c57 Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/marker-default-width-height-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.png index f212019ac81d..eb391f1b9145 100644 Binary files a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.png and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.txt index eaa01be0a030..d8a7e62cb506 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/preserve-aspect-ratio-syntax-expected.txt @@ -14,10 +14,10 @@ layer at (0,0) size 800x600 chunk 1 text run 1 at (0.00,190.00) startOffset 0 endOffset 72 width 264.94: "All svgs below should look the same, all have valid preserveAspectRatio." layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (0,83.33) size 50x99.98 clip at (0,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -25,10 +25,10 @@ layer at (5,5) size 20x20 backgroundClip at (0,83.33) size 50x99.98 clip at (0,8 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (83.33,83.33) size 49.98x99.98 clip at (83.33,83.33) size 49.98x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -36,10 +36,10 @@ layer at (5,5) size 20x20 backgroundClip at (83.33,83.33) size 49.98x99.98 clip RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (166.66,83.33) size 50x99.98 clip at (166.66,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -47,10 +47,10 @@ layer at (5,5) size 20x20 backgroundClip at (166.66,83.33) size 50x99.98 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (250,83.33) size 50x99.98 clip at (250,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -58,10 +58,10 @@ layer at (5,5) size 20x20 backgroundClip at (250,83.33) size 50x99.98 clip at (2 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (333.33,83.33) size 50x99.98 clip at (333.33,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -69,10 +69,10 @@ layer at (5,5) size 20x20 backgroundClip at (333.33,83.33) size 50x99.98 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (416.66,83.33) size 50x99.98 clip at (416.66,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -80,10 +80,10 @@ layer at (5,5) size 20x20 backgroundClip at (416.66,83.33) size 50x99.98 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (0,333.33) size 50x100 clip at (0,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -91,10 +91,10 @@ layer at (5,5) size 20x20 backgroundClip at (0,333.33) size 50x100 clip at (0,33 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (83.33,333.33) size 49.98x100 clip at (83.33,333.33) size 49.98x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -102,10 +102,10 @@ layer at (5,5) size 20x20 backgroundClip at (83.33,333.33) size 49.98x100 clip a RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (166.66,333.33) size 50x100 clip at (166.66,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -113,10 +113,10 @@ layer at (5,5) size 20x20 backgroundClip at (166.66,333.33) size 50x100 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (250,333.33) size 50x100 clip at (250,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-inner-svg-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-inner-svg-expected.txt index f6d863681b36..bac786cc8bbd 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-inner-svg-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-inner-svg-expected.txt @@ -11,6 +11,6 @@ layer at (0,0) size 800x460 layer at (9,51) size 400x400 RenderSVGRoot {svg} at (1,1) size 400x400 RenderSVGViewportContainer at (0,0) size 400x400 -layer at (9,51) size 400x400 clip at (9,51) size 150x150 +layer at (9,51) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 RenderSVGPath {path} at (7,6.09) size 136x136.09 [fill={[type=SOLID] [color=#008000]}] [data="M 143 103 L 143 117 C 143 130.909 112.555 142.185 75 142.185 C 37.4446 142.185 7.00001 130.909 7.00001 117 L 7 117 L 7 103 C 7 89.0906 37.4446 77.8148 75 77.8148 C 112.555 77.8148 143 89.0906 143 103 L 52 72 C 34.3123 70.6562 20.8513 55.5699 21.5237 37.8439 C 22.1961 20.118 36.7613 6.09483 54.5 6.09483 C 72.2387 6.09483 86.8039 20.118 87.4763 37.8439 C 88.1487 55.5699 74.6877 70.6562 57 72"] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-on-symbol-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-on-symbol-expected.txt index 4b45e92337c7..6343b90ab328 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-on-symbol-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-on-symbol-expected.txt @@ -16,6 +16,6 @@ layer at (9,51) size 400x400 RenderSVGPath {path} at (0,0) size 136x136.09 [fill={[type=SOLID] [color=#008000]}] [data="M 143 103 L 143 117 C 143 130.909 112.555 142.185 75 142.185 C 37.4446 142.185 7.00001 130.909 7.00001 117 L 7 117 L 7 103 C 7 89.0906 37.4446 77.8148 75 77.8148 C 112.555 77.8148 143 89.0906 143 103 L 52 72 C 34.3123 70.6562 20.8513 55.5699 21.5237 37.8439 C 22.1961 20.118 36.7613 6.09483 54.5 6.09483 C 72.2387 6.09483 86.8039 20.118 87.4763 37.8439 C 88.1487 55.5699 74.6877 70.6562 57 72"] layer at (9,51) size 360x360 RenderSVGTransformableContainer {use} at (0,0) size 360x360 -layer at (9,51) size 360x360 clip at (9,51) size 150x150 +layer at (9,51) size 360x360 RenderSVGViewportContainer {svg} at (0,0) size 360x360 RenderSVGPath {path} at (7,6.09) size 136x136.09 [fill={[type=SOLID] [color=#008000]}] [data="M 143 103 L 143 117 C 143 130.909 112.555 142.185 75 142.185 C 37.4446 142.185 7.00001 130.909 7.00001 117 L 7 117 L 7 103 C 7 89.0906 37.4446 77.8148 75 77.8148 C 112.555 77.8148 143 89.0906 143 103 L 52 72 C 34.3123 70.6562 20.8513 55.5699 21.5237 37.8439 C 22.1961 20.118 36.7613 6.09483 54.5 6.09483 C 72.2387 6.09483 86.8039 20.118 87.4763 37.8439 C 88.1487 55.5699 74.6877 70.6562 57 72"] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-without-attributes-on-symbol-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-without-attributes-on-symbol-expected.txt index e308c180ff75..4b2ec7667a54 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-without-attributes-on-symbol-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/relative-sized-use-without-attributes-on-symbol-expected.txt @@ -16,6 +16,6 @@ layer at (9,51) size 400x400 RenderSVGPath {path} at (0,0) size 136x136.09 [fill={[type=SOLID] [color=#008000]}] [data="M 143 103 L 143 117 C 143 130.909 112.555 142.185 75 142.185 C 37.4446 142.185 7.00001 130.909 7.00001 117 L 7 117 L 7 103 C 7 89.0906 37.4446 77.8148 75 77.8148 C 112.555 77.8148 143 89.0906 143 103 L 52 72 C 34.3123 70.6562 20.8513 55.5699 21.5237 37.8439 C 22.1961 20.118 36.7613 6.09483 54.5 6.09483 C 72.2387 6.09483 86.8039 20.118 87.4763 37.8439 C 88.1487 55.5699 74.6877 70.6562 57 72"] layer at (9,51) size 400x400 RenderSVGTransformableContainer {use} at (0,0) size 400x400 -layer at (9,51) size 400x400 clip at (9,51) size 150x150 +layer at (9,51) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 RenderSVGPath {path} at (7,6.09) size 136x136.09 [fill={[type=SOLID] [color=#008000]}] [data="M 143 103 L 143 117 C 143 130.909 112.555 142.185 75 142.185 C 37.4446 142.185 7.00001 130.909 7.00001 117 L 7 117 L 7 103 C 7 89.0906 37.4446 77.8148 75 77.8148 C 112.555 77.8148 143 89.0906 143 103 L 52 72 C 34.3123 70.6562 20.8513 55.5699 21.5237 37.8439 C 22.1961 20.118 36.7613 6.09483 54.5 6.09483 C 72.2387 6.09483 86.8039 20.118 87.4763 37.8439 C 88.1487 55.5699 74.6877 70.6562 57 72"] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/root-container-opacity-clip-viewBox-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/root-container-opacity-clip-viewBox-expected.txt index 8c9369200973..eec376cbe5dd 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/root-container-opacity-clip-viewBox-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/root-container-opacity-clip-viewBox-expected.txt @@ -3,6 +3,6 @@ layer at (0,0) size 800x600 layer at (0,0) size 800x600 RenderSVGRoot {svg} at (0,0) size 800x600 RenderSVGViewportContainer at (0,0) size 800x600 -layer at (0,0) size 200x200 backgroundClip at (0,0) size 83x64 clip at (0,0) size 117x116 +layer at (0,0) size 200x200 backgroundClip at (0,0) size 83x64 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGRect {rect} at (-83,-84) size 166x148 [fill={[type=SOLID] [color=#008000]}] [x=-83.00] [y=-84.00] [width=166.00] [height=148.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/shapes-supporting-markers-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/shapes-supporting-markers-expected.png new file mode 100644 index 000000000000..5be91a0e0772 Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/shapes-supporting-markers-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/text-rotated-gradient-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/text-rotated-gradient-expected.txt index 86a02d19e779..80aa841ef7e7 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/text-rotated-gradient-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/text-rotated-gradient-expected.txt @@ -35,7 +35,7 @@ layer at (50,21) size 77x37 RenderSVGText {text} at (0,0) size 77x37 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 77x37 chunk 1 text run 1 at (50.00,50.00) startOffset 0 endOffset 4 width 76.44: "TEST" -layer at (0,0) size 800x600 backgroundClip at (0,121.14) size 374.33x80 clip at (0,0) size 466.67x400 +layer at (0,0) size 800x600 backgroundClip at (0,121.14) size 374.33x80 RenderSVGViewportContainer {svg} at (0,0) size 800x600 layer at (100,71.33) size 77x37 RenderSVGTransformableContainer {g} at (100,71.33) size 76.44x36.67 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-in-symbol-with-offset-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-in-symbol-with-offset-expected.txt index 8a3e9c8090b2..e4c8592323dc 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-in-symbol-with-offset-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-in-symbol-with-offset-expected.txt @@ -19,7 +19,7 @@ layer at (0,0) size 1x2 RenderSVGRect {rect} at (0,0) size 1x2 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=2.00] layer at (0,0) size 100x100 RenderSVGTransformableContainer {use} at (0,0) size 100x100 -layer at (0,0) size 100x100 clip at (0,0) size 2x2 +layer at (0,0) size 100x100 RenderSVGViewportContainer {svg} at (0,0) size 100x100 layer at (0,0) size 1x2 RenderSVGTransformableContainer {g} at (0,0) size 1x2 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg-expected.txt index 9e76ee3dad43..950bc10ec7c6 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg-expected.txt @@ -4,10 +4,10 @@ layer at (0,0) size 400x400 RenderSVGRoot {svg} at (0,0) size 400x400 RenderSVGViewportContainer at (0,0) size 400x400 RenderSVGHiddenContainer {defs} at (0,0) size 400x400 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {use} at (0,0) size 1x1 @@ -16,7 +16,7 @@ layer at (0,0) size 1x1 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 400x400 RenderSVGTransformableContainer {use} at (0,0) size 400x400 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {g} at (0,0) size 1x1 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg1-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg1-expected.txt index 5c3a46f895f0..8d0e29e3658c 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg1-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg1-expected.txt @@ -4,11 +4,11 @@ layer at (0,0) size 200x200 RenderSVGRoot {svg} at (0,0) size 200x200 RenderSVGViewportContainer at (0,0) size 200x200 RenderSVGHiddenContainer {defs} at (0,0) size 200x200 -layer at (0,0) size 200x200 clip at (0,0) size 2x2 +layer at (0,0) size 200x200 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 200x200 RenderSVGTransformableContainer {use} at (0,0) size 200x200 -layer at (0,0) size 200x200 clip at (0,0) size 2x2 +layer at (0,0) size 200x200 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg2-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg2-expected.txt index f358622c93d0..1da76fc58468 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg2-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-svg2-expected.txt @@ -5,7 +5,7 @@ layer at (0,0) size 400x400 RenderSVGViewportContainer at (0,0) size 400x400 RenderSVGHiddenContainer {defs} at (0,0) size 400x400 RenderSVGHiddenContainer {symbol} at (0,0) size 1x1 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 1x1 @@ -15,7 +15,7 @@ layer at (0,0) size 1x1 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 400x400 RenderSVGTransformableContainer {use} at (0,0) size 400x400 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {g} at (0,0) size 1x1 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol-expected.txt index aca688826ea7..8b727bfce408 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol-expected.txt @@ -14,7 +14,7 @@ layer at (0,0) size 1x1 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 400x400 RenderSVGTransformableContainer {use} at (0,0) size 400x400 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {g} at (0,0) size 1x1 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol1-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol1-expected.txt index 6303b50a7562..a1716da977b5 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol1-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol1-expected.txt @@ -8,6 +8,6 @@ layer at (0,0) size 200x200 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 200x200 RenderSVGTransformableContainer {use} at (0,0) size 200x200 -layer at (0,0) size 200x200 clip at (0,0) size 2x2 +layer at (0,0) size 200x200 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol2-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol2-expected.txt index c2546a1549f9..f8d197b4d402 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol2-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/use-transfer-width-height-properties-to-symbol2-expected.txt @@ -6,7 +6,7 @@ layer at (0,0) size 400x400 RenderSVGHiddenContainer {defs} at (0,0) size 400x400 RenderSVGHiddenContainer {symbol} at (0,0) size 1x1 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {use} at (0,0) size 1x1 @@ -15,7 +15,7 @@ layer at (0,0) size 1x1 RenderSVGRect {rect} at (0,0) size 1x1 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=1.00] [height=1.00] layer at (0,0) size 400x400 RenderSVGTransformableContainer {use} at (0,0) size 400x400 -layer at (0,0) size 400x400 clip at (0,0) size 2x2 +layer at (0,0) size 400x400 RenderSVGViewportContainer {svg} at (0,0) size 400x400 layer at (0,0) size 1x1 RenderSVGTransformableContainer {g} at (0,0) size 1x1 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.png new file mode 100644 index 000000000000..99854a5a02ab Binary files /dev/null and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.txt index 98aa3edc9b6e..4b4a0fcfc5d2 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/custom/viewbox-syntax-expected.txt @@ -27,7 +27,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (0,83.33) size 50x99.98 clip at (0,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -38,7 +38,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (83.33,83.33) size 49.98x99.98 clip at (83.33,83.33) size 49.98x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -49,7 +49,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (166.66,83.33) size 50x99.98 clip at (166.66,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -60,7 +60,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (250,83.33) size 50x99.98 clip at (250,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -71,7 +71,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (333.33,83.33) size 50x99.98 clip at (333.33,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -82,7 +82,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (416.66,83.33) size 50x99.98 clip at (416.66,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -93,7 +93,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (500,83.33) size 50x99.98 clip at (500,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -104,7 +104,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (583.33,83.33) size 50x99.98 clip at (583.33,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -115,7 +115,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (666.66,83.33) size 50x99.98 clip at (666.66,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -126,7 +126,7 @@ layer at (0,0) size 30x60 layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (750,83.33) size 50x99.98 clip at (750,83.33) size 50x99.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -134,10 +134,10 @@ layer at (5,5) size 20x20 backgroundClip at (750,83.33) size 50x99.98 clip at (7 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (0,333.33) size 50x100 clip at (0,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -145,10 +145,10 @@ layer at (5,5) size 20x20 backgroundClip at (0,333.33) size 50x100 clip at (0,33 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (83.33,333.33) size 49.98x100 clip at (83.33,333.33) size 49.98x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -156,10 +156,10 @@ layer at (5,5) size 20x20 backgroundClip at (83.33,333.33) size 49.98x100 clip a RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (166.66,333.33) size 50x100 clip at (166.66,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -167,10 +167,10 @@ layer at (5,5) size 20x20 backgroundClip at (166.66,333.33) size 50x100 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (250,333.33) size 50x100 clip at (250,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -189,10 +189,10 @@ layer at (5,5) size 20x20 backgroundClip at (333.33,333.33) size 50x100 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (416.66,333.33) size 50x100 clip at (416.66,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -200,10 +200,10 @@ layer at (5,5) size 20x20 backgroundClip at (416.66,333.33) size 50x100 clip at RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (500,333.33) size 50x100 clip at (500,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -211,10 +211,10 @@ layer at (5,5) size 20x20 backgroundClip at (500,333.33) size 50x100 clip at (50 RenderSVGPath {path} at (5,14) size 10x4 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#000000]}] [data="M 10 19 L 15 23 L 20 19"] layer at (0,0) size 30x60 RenderSVGTransformableContainer {g} at (0,0) size 30x60 -layer at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,0) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (583.33,333.33) size 50x100 clip at (583.33,333.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/text/text-viewbox-rescale-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/text/text-viewbox-rescale-expected.txt index dc47ed468f1c..c040df5fa750 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/text/text-viewbox-rescale-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/text/text-viewbox-rescale-expected.txt @@ -6,7 +6,7 @@ layer at (0,0) size 800x600 layer at (0,0) size 200x200 RenderSVGRoot {svg} at (0,0) size 200x200 RenderSVGViewportContainer at (0,0) size 200x200 -layer at (0,0) size 200x200 clip at (0,0) size 1x1 +layer at (0,0) size 200x200 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGText {text} at (0,0) size 1x1 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 1x1 @@ -15,7 +15,7 @@ layer at (0,0) size 200x200 clip at (0,0) size 1x1 RenderSVGInlineText {#text} at (0,0) size 1x1 chunk 1 text run 1 at (0.56,0.30) startOffset 0 endOffset 4 width 0.24: "PASS" RenderSVGInlineText {#text} at (0,0) size 0x0 -layer at (0,0) size 200x200 clip at (0,0) size 1x1 +layer at (0,0) size 200x200 RenderSVGViewportContainer {svg} at (0,0) size 200x200 RenderSVGText {text} at (0,0) size 1x1 contains 1 chunk(s) RenderSVGInlineText {#text} at (0,0) size 1x1 diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.png index 7c5d248bbaf2..b77bd28ed052 100644 Binary files a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.png and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.txt index c530700eb90c..d1fbfa4c2ea0 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/page/zoom-coords-viewattr-01-b-expected.txt @@ -49,7 +49,7 @@ layer at (0,-28.05) size 112x59 backgroundClip at (0,0) size 1130.39x842.39 clip layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,13.05) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (284.39,187.19) size 117x70.19 clip at (284.39,187.19) size 117x70.19 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -61,10 +61,10 @@ layer at (0,-13.05) size 50x44 backgroundClip at (0,0) size 1130.39x842.39 clip RenderSVGInlineText {#text} at (0,0) size 25x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 24.00: "xMid*" RenderSVGRect {rect} at (0.50,13.55) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 48.34x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,13.05) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (448.17,187.19) size 117.03x70.19 clip at (448.17,187.19) size 117.03x70.19 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -76,10 +76,10 @@ layer at (0,-13.05) size 50x44 backgroundClip at (0,0) size 1130.39x842.39 clip RenderSVGInlineText {#text} at (0,0) size 26x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 25.50: "xMax*" RenderSVGRect {rect} at (0.50,13.55) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 30.02x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,13.05) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (284.38,304.19) size 117.03x70.19 clip at (284.38,304.19) size 117.03x70.19 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -95,10 +95,10 @@ layer at (0,-28.05) size 124x89 backgroundClip at (0,0) size 1130.39x842.39 clip RenderSVGInlineText {#text} at (0,0) size 27x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMin" RenderSVGRect {rect} at (0.50,13.55) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x60 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,13.05) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (705.59,187.19) size 70.19x140.39 clip at (705.59,187.19) size 70.19x140.39 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -110,10 +110,10 @@ layer at (0,-13.05) size 30x74 backgroundClip at (0,0) size 1130.39x842.39 clip RenderSVGInlineText {#text} at (0,0) size 27x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMid" RenderSVGRect {rect} at (0.50,13.55) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,13.05) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (822.58,187.19) size 70.19x140.39 clip at (822.58,187.19) size 70.19x140.39 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -125,10 +125,10 @@ layer at (0,-13.05) size 30x74 backgroundClip at (0,0) size 1130.39x842.39 clip RenderSVGInlineText {#text} at (0,0) size 28x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 27.50: "*YMax" RenderSVGRect {rect} at (0.50,13.55) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,13.05) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (939.58,187.19) size 70.19x140.39 clip at (939.58,187.19) size 70.19x140.39 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.png b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.png index e159733c8ea2..c83ba0fee370 100644 Binary files a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.png and b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.png differ diff --git a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.txt b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.txt index 935117c0eb3f..ed0e2e14f33e 100644 --- a/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.txt +++ b/LayoutTests/platform/mac-tahoe-wk2-lbse-text/svg/zoom/text/zoom-coords-viewattr-01-b-expected.txt @@ -49,7 +49,7 @@ layer at (0,-27.95) size 112x58 backgroundClip at (0,0) size 800x600 clip at (0, layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.95) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (200,133.33) size 83.33x50 clip at (200,133.33) size 83.33x50 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -61,10 +61,10 @@ layer at (0,-12.95) size 50x43 backgroundClip at (0,0) size 800x600 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 25x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 24.00: "xMid*" RenderSVGRect {rect} at (0.50,13.45) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 48.34x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.95) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (316.64,133.33) size 83.36x50 clip at (316.64,133.33) size 83.36x50 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -76,10 +76,10 @@ layer at (0,-12.95) size 50x43 backgroundClip at (0,0) size 800x600 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 26x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 25.50: "xMax*" RenderSVGRect {rect} at (0.50,13.45) size 49x29 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=49.00] [height=29.00] -layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 clip at (0,0) size 30.02x40 +layer at (0,0) size 50x31 backgroundClip at (0,0) size 30x40 RenderSVGViewportContainer {svg} at (0,12.95) size 50x30 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (199.98,216.66) size 83.36x49.98 clip at (199.98,216.66) size 83.36x49.98 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -95,10 +95,10 @@ layer at (0,-27.95) size 124x88 backgroundClip at (0,0) size 800x600 clip at (0, RenderSVGInlineText {#text} at (0,0) size 27x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMin" RenderSVGRect {rect} at (0.50,13.45) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x60 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.95) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (500,133.33) size 50x100 clip at (500,133.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -110,10 +110,10 @@ layer at (0,-12.95) size 30x73 backgroundClip at (0,0) size 800x600 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 27x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 26.00: "*YMid" RenderSVGRect {rect} at (0.50,13.45) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x50 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.95) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (583.33,133.33) size 50x100 clip at (583.33,133.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] @@ -125,10 +125,10 @@ layer at (0,-12.95) size 30x73 backgroundClip at (0,0) size 800x600 clip at (0,0 RenderSVGInlineText {#text} at (0,0) size 28x11 chunk 1 text run 1 at (0.00,-5.00) startOffset 0 endOffset 5 width 27.50: "*YMax" RenderSVGRect {rect} at (0.50,13.45) size 29x59 [stroke={[type=SOLID] [color=#0000FF]}] [x=0.50] [y=0.50] [width=29.00] [height=59.00] -layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 clip at (0,0) size 30x40 +layer at (0,0) size 30x61 backgroundClip at (0,0) size 30x60 RenderSVGViewportContainer {svg} at (0,12.95) size 30x60 RenderSVGRect {rect} at (0.50,0.50) size 29x39 [stroke={[type=SOLID] [color=#FF0000]}] [fill={[type=SOLID] [color=#000000]}] [x=0.50] [y=0.50] [width=29.00] [height=39.00] -layer at (5,5) size 20x20 backgroundClip at (666.66,133.33) size 50x100 clip at (666.66,133.33) size 50x100 +layer at (5,5) size 20x20 RenderSVGTransformableContainer {g} at (5,5) size 20x20 RenderSVGEllipse {circle} at (0,0) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=15.00] [cy=15.00] [r=10.00] RenderSVGEllipse {circle} at (5.50,5.50) size 3x3 [fill={[type=SOLID] [color=#000000]}] [cx=12.00] [cy=12.00] [r=1.50] diff --git a/LayoutTests/platform/mac-wk2/TestExpectations b/LayoutTests/platform/mac-wk2/TestExpectations index 486a1a6d5e0c..76313f082be4 100644 --- a/LayoutTests/platform/mac-wk2/TestExpectations +++ b/LayoutTests/platform/mac-wk2/TestExpectations @@ -2471,4 +2471,21 @@ webkit.org/b/322051 [ Release ] media/picture-in-picture/picture-in-picture-inte [ Tahoe+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame.https.html [ Failure ] [ Tahoe+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame.https.html [ Failure ] -webkit.org/b/321323 [ Tahoe+ ] http/tests/websocket/tests/hybi/inspector/before-load.html [ Failure ] \ No newline at end of file +webkit.org/b/321323 [ Tahoe+ ] http/tests/websocket/tests/hybi/inspector/before-load.html [ Failure ] + +# webkit.org/b/322840 REGRESSION(318498@main): [Tahoe] 11 imported/w3c/web-platform-tests/encrypted-media/drm-mp4 tests are a constant CRASH +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-encrypted-clear-sources.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-playduration.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-after-update.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-immediately.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-setMediaKeys-onencrypted.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-two-videos.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary-waitingforkey.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-playback-temporary.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-playback.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-setmediakeys-again-after-resetting-src.https.html [ Failure Crash ] +[ Tahoe Debug ] imported/w3c/web-platform-tests/encrypted-media/drm-mp4-waiting-for-a-key.https.html [ Failure Crash ] + +webkit.org/b/322847 [ Debug ] imported/w3c/web-platform-tests/css/css-grid/grid-lanes/subgrid/grid-subgridded-to-grid-lanes/baseline/row-grid-lanes-item-baseline-subgrid-001.html [ Crash ] +webkit.org/b/322847 [ Debug ] imported/w3c/web-platform-tests/css/css-grid/grid-lanes/subgrid/grid-subgridded-to-grid-lanes/baseline/row-grid-lanes-item-baseline-subgrid-004.html [ Crash ] +webkit.org/b/322847 [ Debug ] imported/w3c/web-platform-tests/css/css-grid/grid-lanes/subgrid/grid-subgridded-to-grid-lanes/baseline/row-grid-lanes-item-baseline-subgrid-005.html [ Crash ] \ No newline at end of file diff --git a/LayoutTests/platform/mac/TestExpectations b/LayoutTests/platform/mac/TestExpectations index e1b4ac5905db..d149ca079c36 100644 --- a/LayoutTests/platform/mac/TestExpectations +++ b/LayoutTests/platform/mac/TestExpectations @@ -102,6 +102,9 @@ fast/images/heic-as-background-image.html [ Pass ] # Video as an image source is only supported on macOS and iOS. fast/images/video-as-image.html [ Pass ] +# ImageIO rejects an acTL declaring zero frames, so the default image never decodes. +fast/images/apng-acTL-zero-frame-count.html [ Skip ] + # Enabled in rdar://102830993 fast/images/mac/play-all-pause-all-animations-context-menu-items.html [ Skip ] @@ -1935,8 +1938,6 @@ webkit.org/b/258181 [ Debug ] inspector/debugger/async-stack-trace-truncate.html webkit.org/b/236128 imported/w3c/web-platform-tests/html/user-activation/activation-trigger-mouse-right.html [ Skip ] -webkit.org/b/252322 [ X86_64 ] media/media-source/media-source-video-renders.html [ ImageOnlyFailure ] # rdar://180537206 - webkit.org/b/259712 media/media-source/media-source-paint-after-display-none.html [ Skip ] # rdar://110876540 ASSERTION FAILED: firstChild(): [ macOS ] (258183) @@ -2468,8 +2469,8 @@ imported/w3c/web-platform-tests/storage-access-api/requestStorageAccess-web-sock # rdar://172914523 [macOS 27] imported/w3c/web-platform-tests/svg/shapes/reftests/pathlength-002.svg is a constant IMAGE failure [ GoldenGate ] imported/w3c/web-platform-tests/svg/shapes/reftests/pathlength-002.svg [ ImageOnlyFailure ] -# rdar://173032378 REGRESSION(304821@main): [macOS 27] imported/w3c/web-platform-tests/css/css-ui/text-overflow-with-selection.html is a constant IMAGE failure -[ GoldenGate ] imported/w3c/web-platform-tests/css/css-ui/text-overflow-with-selection.html [ ImageOnlyFailure ] +# rdar://173032378 REGRESSION(304821@main): [macOS 27] imported/w3c/web-platform-tests/css/css-overflow/text-overflow-with-selection.html is a constant IMAGE failure +[ GoldenGate ] imported/w3c/web-platform-tests/css/css-overflow/text-overflow-with-selection.html [ ImageOnlyFailure ] # rdar://173034292 REGRESSION(macOS 27?): [macOS 27] media/modern-media-controls/tracks-support/sorted-by-user-preferred-languages.html is a constant TEXT failure [ GoldenGate ] media/modern-media-controls/tracks-support/sorted-by-user-preferred-languages.html [ Failure ] diff --git a/LayoutTests/platform/wpe/TestExpectations b/LayoutTests/platform/wpe/TestExpectations index 8bea42cc0bee..0f1324dd7b06 100644 --- a/LayoutTests/platform/wpe/TestExpectations +++ b/LayoutTests/platform/wpe/TestExpectations @@ -25,7 +25,7 @@ imported/w3c/web-platform-tests/css/compositing/mix-blend-mode/mix-blend-mode-in webkit.org/b/307586 [ Release ] imported/w3c/web-platform-tests/css/css-view-transitions/no-raf-while-render-blocked.html [ Failure Pass ] -imported/w3c/web-platform-tests/css/css-ui/text-overflow-005.html [ Pass ] +imported/w3c/web-platform-tests/css/css-overflow/text-overflow-005.html [ Pass ] imported/w3c/web-platform-tests/css/css-display/run-in/quotes-applies-to-011.xht [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-text/boundary-shaping/boundary-shaping-004.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-text/boundary-shaping/boundary-shaping-005.html [ ImageOnlyFailure ] @@ -869,6 +869,10 @@ media/media-source/media-detachablemse-append.html [ Timeout Pass ] imported/w3c/web-platform-tests/css/css-overflow/overflow-auto-scrolling-with-margin-and-transform.html [ Skip ] +imported/w3c/web-platform-tests/css/css-overflow/clip-002.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/clip-004.html [ ImageOnlyFailure ] +imported/w3c/web-platform-tests/css/css-overflow/clip-005.html [ ImageOnlyFailure ] + webkit.org/b/228311 imported/w3c/web-platform-tests/css/css-scoping/css-scoping-shadow-dynamic-remove-style-detached.html [ Pass Failure ] fast/events/mouse-cursor-pseudo-elements.html [ Failure Pass ] @@ -1326,3 +1330,4 @@ webkit.org/b/322026 [ arm64 ] imported/w3c/web-platform-tests/wasm/core/f64_cmp. webkit.org/b/321789 animations/no-style-recalc-during-accelerated-animation.html [ Failure Pass ] webkit.org/b/322637 [ Debug ] imported/w3c/web-platform-tests/fullscreen/model/remove-last.html [ Pass Failure ] webkit.org/b/322639 [ Debug ] imported/w3c/web-platform-tests/html/semantics/popovers/popover-remove-attribute-during-focusing-steps.html [ Pass Failure ] +webkit.org/b/322813 [ arm64 ] imported/w3c/web-platform-tests/css/css-grid/subgrid/subgrid-baseline-018.html [ Crash Pass Timeout ] diff --git a/Source/JavaScriptCore/API/tests/Regress141275.mm b/Source/JavaScriptCore/API/tests/Regress141275.mm index fd13edca35d9..ece269daa477 100644 --- a/Source/JavaScriptCore/API/tests/Regress141275.mm +++ b/Source/JavaScriptCore/API/tests/Regress141275.mm @@ -107,7 +107,7 @@ - (instancetype)init { self = [super init]; if (self) { - _jsSourcePerformQueue = dispatch_queue_create("JSTEval", DISPATCH_QUEUE_CONCURRENT); + _jsSourcePerformQueue = dispatch_queue_create("JSTEval", concurrentQueueWithAutoreleasePoolAttrSingleton()); _allScriptsDone = dispatch_semaphore_create(0); diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index fa79d0d4aade..b0f7305a55b4 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -2076,6 +2076,26 @@ if(USE_INSPECTOR_SOCKET_SERVER) ) endif() +# The corpse memory-analysis support is built on Mach task and corpse APIs, so +# its headers have no content off Darwin and there is nothing to build or export. +if (APPLE) + list(APPEND JavaScriptCore_PRIVATE_INCLUDE_DIRECTORIES + "${JAVASCRIPTCORE_DIR}/corpse" + ) + list(APPEND JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS + corpse/CorpseAddress.h + corpse/CorpseByteParser.h + corpse/CorpseClient.h + corpse/CorpseError.h + corpse/CorpseExportsTrie.h + corpse/CorpseProcess.h + corpse/CorpseRegion.h + corpse/CorpseSnapshot.h + corpse/CorpseSymbol.h + corpse/CorpseThread.h + ) +endif () + # GENERATOR 1-B: particular LUT creator (for 1 file only) GENERATE_HASH_LUT(${CMAKE_CURRENT_SOURCE_DIR}/parser/Keywords.table ${JavaScriptCore_DERIVED_SOURCES_DIR}/Lexer.lut.h) @@ -2385,6 +2405,14 @@ add_custom_target(JavaScriptCoreSharedScripts DEPENDS ${JavaScriptCore_SCRIPTS}) add_dependencies(JavaScriptCore JavaScriptCoreSharedScripts ${JavaScriptCore_EXTRA_DEPENDENCIES}) add_dependencies(JavaScriptCoreSharedScripts JSCBuiltins) +# The corpse code is part of JavaScriptCoreTools, which ships as a static library used +# only by tools for assisting in the development of JavaScriptCore and WebKit. This code +# is not needed for JavaScriptCore and WebKit functionality as a browser engine. The +# corpse code rely on Mach APIs which are only available on Apple platforms. +if (APPLE) + add_subdirectory(corpse) +endif () + if (ENABLE_JAVASCRIPT_SHELL) add_subdirectory(shell) endif () diff --git a/Source/JavaScriptCore/Configurations/Mya.xcconfig b/Source/JavaScriptCore/Configurations/Mya.xcconfig new file mode 100644 index 000000000000..32bdfefbe5a7 --- /dev/null +++ b/Source/JavaScriptCore/Configurations/Mya.xcconfig @@ -0,0 +1,43 @@ +// Copyright (C) 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 +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "JSC.xcconfig" + +PRODUCT_NAME = mya; + +INSTALL_PATH = /usr/local/bin; + +// Not installed for simulator or Catalyst builds. +WK_LIB_JSC_TOOLS_SIMULATOR = NO; +WK_LIB_JSC_TOOLS_SIMULATOR[sdk=*simulator*] = YES; +WK_LIB_JSC_TOOLS_SUPPORTED = $(WK_NOT_$(WK_LIB_JSC_TOOLS_UNSUPPORTED)); +WK_LIB_JSC_TOOLS_UNSUPPORTED = $(WK_OR_$(WK_LIB_JSC_TOOLS_SIMULATOR)_$(WK_CHECK_CATALYST)); + +SKIP_INSTALL = $(WK_LIB_JSC_TOOLS_SKIP_INSTALL_$(WK_LIB_JSC_TOOLS_UNSUPPORTED)); +WK_LIB_JSC_TOOLS_SKIP_INSTALL_YES = YES; +WK_LIB_JSC_TOOLS_SKIP_INSTALL_NO = NO; + +OTHER_LDFLAGS = $(inherited) $(WK_LIB_JSC_TOOLS_LDFLAGS_$(WK_LIB_JSC_TOOLS_SUPPORTED)); +WK_LIB_JSC_TOOLS_LDFLAGS_YES = -lJavaScriptCoreTools; + +OTHER_CODE_SIGN_FLAGS[sdk=iphone*] = -i com.apple.jsc.mya --entitlements ${WK_PROCESSED_XCENT_FILE}; diff --git a/Source/JavaScriptCore/Configurations/TestLibJSCTools.xcconfig b/Source/JavaScriptCore/Configurations/TestLibJSCTools.xcconfig new file mode 100644 index 000000000000..6f33bf0408e5 --- /dev/null +++ b/Source/JavaScriptCore/Configurations/TestLibJSCTools.xcconfig @@ -0,0 +1,35 @@ +// Copyright (C) 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 +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "TestExecutable.xcconfig" + +// We build and install testLibJSCTools for the simulator and MacCatalyst but it does nothing +// on these platforms. We do this so that run-javascriptcore-tests do not error out for a missing +// testLibJSCTools executable. +WK_LIB_JSC_TOOLS_SIMULATOR = NO; +WK_LIB_JSC_TOOLS_SIMULATOR[sdk=*simulator*] = YES; +WK_LIB_JSC_TOOLS_SUPPORTED = $(WK_NOT_$(WK_LIB_JSC_TOOLS_UNSUPPORTED)); +WK_LIB_JSC_TOOLS_UNSUPPORTED = $(WK_OR_$(WK_LIB_JSC_TOOLS_SIMULATOR)_$(WK_CHECK_CATALYST)); + +OTHER_LDFLAGS = $(inherited) $(WK_LIB_JSC_TOOLS_LDFLAGS_$(WK_LIB_JSC_TOOLS_SUPPORTED)); +WK_LIB_JSC_TOOLS_LDFLAGS_YES = -lJavaScriptCoreTools; diff --git a/Source/JavaScriptCore/Configurations/libJavaScriptCoreTools.xcconfig b/Source/JavaScriptCore/Configurations/libJavaScriptCoreTools.xcconfig new file mode 100644 index 000000000000..412a878ef1fe --- /dev/null +++ b/Source/JavaScriptCore/Configurations/libJavaScriptCoreTools.xcconfig @@ -0,0 +1,57 @@ +// Copyright (C) 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 +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// JavaScriptCoreTools is a tools library that is for implementing tools to assist +// in JavaScriptCore and WebKit development. It builds on JavaScriptCore, but does +// not contain any functionality that is part of core JSC, and it is not needed for +// implementing browser engines. +// +// JavaScriptCoreTools is packaged as a static library, and meant only to be linked +// by tools that need it. Its headers are included as private headers of JavaScriptCore. +// This allows JavaScriptCore and JavaScriptCoreTools to be revision locked, and +// built in tandem to prevent bit rot from creeping in. +#include "BaseTarget.xcconfig" + +PRODUCT_NAME = JavaScriptCoreTools; + +// Disable IR PGO profile generation for JavaScriptCoreTools. +WK_PGO_GEN_FLAGS = ; + +// Not built for simulator or Catalyst builds. +WK_LIB_JSC_TOOLS_SIMULATOR = NO; +WK_LIB_JSC_TOOLS_SIMULATOR[sdk=*simulator*] = YES; +WK_LIB_JSC_TOOLS_UNSUPPORTED = $(WK_OR_$(WK_LIB_JSC_TOOLS_SIMULATOR)_$(WK_CHECK_CATALYST)); + +EXCLUDED_SOURCE_FILE_NAMES = $(WK_LIB_JSC_TOOLS_EXCLUDED_$(WK_LIB_JSC_TOOLS_UNSUPPORTED)); +WK_LIB_JSC_TOOLS_EXCLUDED_YES = *; + +// Installed to /usr/local/lib, alongside libWTF.a and libbmalloc.a. +INSTALL_PATH = $(WK_LIBRARY_INSTALL_PATH); +SKIP_INSTALL = $(WK_LIB_JSC_TOOLS_SKIP_INSTALL_$(WK_LIB_JSC_TOOLS_UNSUPPORTED)); +WK_LIB_JSC_TOOLS_SKIP_INSTALL_YES = YES; +WK_LIB_JSC_TOOLS_SKIP_INSTALL_NO = NO; +STRIP_INSTALLED_PRODUCT = NO; + +// The sources include "config.h" and their own headers from the source tree, +// plus JavaScriptCore's generated and private headers. +HEADER_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/corpse "$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders" $(inherited); diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 62dc0c1cb3bd..eb7e1593d232 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -76,6 +76,8 @@ dependencies = ( 932F5BE70822A1C700736975 /* PBXTargetDependency */, 5D69E912152BE5470028D720 /* PBXTargetDependency */, + D3934A4385F631C04057F7E7 /* PBXTargetDependency */, + 5F40739EF054554602787C41 /* PBXTargetDependency */, 5D6B2A57152B9E2E005231DE /* PBXTargetDependency */, ); name = All; @@ -1527,6 +1529,9 @@ 92B4EF902D71C3650068CB55 /* LLVMProfiling.h in Headers */ = {isa = PBXBuildFile; fileRef = 92B4EF8F2D71C3650068CB55 /* LLVMProfiling.h */; settings = {ATTRIBUTES = (Private, ); }; }; 93052C350FB792190048FDC3 /* ParserArena.h in Headers */ = {isa = PBXBuildFile; fileRef = 93052C330FB792190048FDC3 /* ParserArena.h */; settings = {ATTRIBUTES = (Private, ); }; }; 932F5BDD0822A1C700736975 /* jsc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45E12D8806A49B0F00E9DF84 /* jsc.cpp */; }; + 6DCC8B386903B87B8A4E5A26 /* mya.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 806620AA0612E27A5093C379 /* mya.cpp */; }; + ACB50B356C9AA8E90AA3DF50 /* JavaScriptCore.framework in Product Dependencies */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; + D9BBE216687E30084BD44207 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; 933040040E6A749400786E6A /* SmallStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 93303FEA0E6A72C000786E6A /* SmallStrings.h */; settings = {ATTRIBUTES = (Private, ); }; }; 93BFC6D929B344C90030D7BE /* GlobalObjectMethodTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 93BFC6D829B344C80030D7BE /* GlobalObjectMethodTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; 95CA6AD328809E010062D5EC /* ImplementationVisibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 95CA6AD228809E010062D5EC /* ImplementationVisibility.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1828,6 +1833,34 @@ BC11667B0E199C05008066DD /* InternalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11667A0E199C05008066DD /* InternalFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC1167DA0E19BCC9008066DD /* JSCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1167D80E19BCC9008066DD /* JSCell.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */ = {isa = PBXBuildFile; fileRef = 1482B78A0A4305AB00517CFC /* APICast.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0D9C2E68ACFF010D91916993 /* CorpseProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 55D0F2DD9CA70132D5104B34 /* CorpseProcess.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 3A7C1E5D9B0F4A2681C34D07 /* CorpseRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F41D6082A3E4B57C0768DB1 /* CorpseRegion.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 725D045D67B3017EAC56561C /* CorpseAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C6EB9C72F84ED87DF23277A /* CorpseAddress.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 80B96670131FB9EBB9AD49CC /* CorpseClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CBE14E70FB474FCFCD6A8B9 /* CorpseClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2EB941F3198AE0BD86A2324 /* CorpseClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 422D2FE4AA2401EA8C3F2D8F /* CorpseClient.cpp */; }; + 85428E7BE0B3557DD2988043 /* CorpseError.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DDA7A78AD90B64B97AE329C /* CorpseError.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 121D90BB8171A66F1922D548 /* CorpseError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AC15166B6F71CD338DD8D6F /* CorpseError.cpp */; }; + 7E83C43817D785F3003DC41B /* CorpseExportsTrie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C43617D785F3003DC41B /* CorpseExportsTrie.cpp */; }; + 7E83C42417D785F3003DC41B /* CorpseByteParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C42317D785F3003DC41B /* CorpseByteParser.cpp */; }; + 7E83C42817D785F3003DC41B /* CorpseByteParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E83C42217D785F3003DC41B /* CorpseByteParser.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 7E83C42717D785F3003DC41B /* CorpseByteParserTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C42617D785F3003DC41B /* CorpseByteParserTest.cpp */; }; + 7E83C42B17D785F3003DC41B /* CorpseAddressTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C42917D785F3003DC41B /* CorpseAddressTest.cpp */; }; + 7E83C42E17D785F3003DC41B /* CorpseProcessTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C42C17D785F3003DC41B /* CorpseProcessTest.cpp */; }; + 7E83C43117D785F3003DC41B /* CorpseRegionTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C42F17D785F3003DC41B /* CorpseRegionTest.cpp */; }; + 7E83C43417D785F3003DC41B /* CorpseThreadTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C43217D785F3003DC41B /* CorpseThreadTest.cpp */; }; + 7E83C40B17D785F3003DC41B /* CorpseExportsTrieTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C40217D785F3003DC41B /* CorpseExportsTrieTest.cpp */; }; + 7E83C41017D785F3003DC41B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF0F569B2E334C90002A232A /* Foundation.framework */; }; + 7E83C40F17D785F3003DC41B /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; + 7E83C40C17D785F3003DC41B /* LibJSCToolsTestUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C40417D785F3003DC41B /* LibJSCToolsTestUtilities.cpp */; }; + 7E83C40D17D785F3003DC41B /* CorpseSnapshotTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C40617D785F3003DC41B /* CorpseSnapshotTest.cpp */; }; + 7E83C40E17D785F3003DC41B /* CorpseSymbolTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C40817D785F3003DC41B /* CorpseSymbolTest.cpp */; }; + 7E83C40A17D785F3003DC41B /* testLibJSCTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E83C40017D785F3003DC41B /* testLibJSCTools.cpp */; }; + 7E83C43717D785F3003DC41B /* CorpseExportsTrie.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E83C43517D785F3003DC41B /* CorpseExportsTrie.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 56C6C2B7EBDCC63B6ECEA9AD /* CorpseThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 211E3D6CA97F31CEB385A75A /* CorpseThread.h */; settings = {ATTRIBUTES = (Private, ); }; }; + EF648B9EEAF54C44048B416A /* CorpseThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 960BD2B783EAEBE3233F91BF /* CorpseThread.cpp */; }; + CA47D093D003440A28D15924 /* CorpseSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 94711688984F16F71D615DE5 /* CorpseSnapshot.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 5601486802533982ACC870BE /* CorpseSymbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F1FA0900D09DF06EE63F7D2 /* CorpseSymbol.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 377C8C2416AE3DF90650C0E9 /* CorpseSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8D1735B28066A3B1D756ECC /* CorpseSymbol.cpp */; }; BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7952070E15E8A800A898AB /* ArrayConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A84E0255597D01FF60F7 /* ArrayPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C3EC0E16F5CD00B34460 /* BooleanObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 704FD35305697E6D003DBED9 /* BooleanObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2131,6 +2164,9 @@ E392E6F924D25FA900B20767 /* B3BottomTupleValue.h in Headers */ = {isa = PBXBuildFile; fileRef = E392E6F724D25FA600B20767 /* B3BottomTupleValue.h */; }; E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E393ADD71FE702CC0022D681 /* WeakMapImplInlines.h */; }; E39440542F276A4A0055F0DB /* Binja.c in Sources */ = {isa = PBXBuildFile; fileRef = E3380F572F271A400097D76C /* Binja.c */; }; + C366EA5039A3B51405995EA6 /* CorpseProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68BBF9CBD85C8635B2B8385F /* CorpseProcess.cpp */; }; + 5E2B94A17C6D40F3B85219CE /* CorpseRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8503B7E641A29DF5B0E3742 /* CorpseRegion.cpp */; }; + 0946712DEC51E0E86C4A49E3 /* CorpseSnapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E906BE4CC29012A83A8F299 /* CorpseSnapshot.cpp */; }; E3952C182F1DDF5700F5BEE8 /* B3WasmStructGetValue.h in Headers */ = {isa = PBXBuildFile; fileRef = E3952C122F1DDF5700F5BEE8 /* B3WasmStructGetValue.h */; }; E3952C192F1DDF5700F5BEE8 /* B3WasmStructNewValue.h in Headers */ = {isa = PBXBuildFile; fileRef = E3952C142F1DDF5700F5BEE8 /* B3WasmStructNewValue.h */; }; E3952C1A2F1DDF5700F5BEE8 /* B3WasmStructFieldValue.h in Headers */ = {isa = PBXBuildFile; fileRef = E3952C102F1DDF5700F5BEE8 /* B3WasmStructFieldValue.h */; }; @@ -2527,6 +2563,48 @@ /* End PBXBuildRule section */ /* Begin PBXContainerItemProxy section */ + 6044D4B120B01FBCA9BCFBE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 49D9C56EC7911960C24239F3; + remoteInfo = JavaScriptCoreTools; + }; + A1B2C3000AE5B4A700C0FFEE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 65FB3F6609D11E9100F49DEB; + remoteInfo = "Derived Sources"; + }; + A1B2C30004E5B4A700C0FFEE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 49D9C56EC7911960C24239F3; + remoteInfo = JavaScriptCoreTools; + }; + A1B2C30006E5B4A700C0FFEE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6B03652E1F50D87F0DEC6B42; + remoteInfo = mya; + }; + A1B2C30008E5B4A700C0FFEE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7E83C41317D785F3003DC41B; + remoteInfo = testLibJSCTools; + }; + 291A8D565940996D3CA021C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 49D9C56EC7911960C24239F3; + remoteInfo = JavaScriptCoreTools; + }; 074D7E092E3D3B6800CD38C6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -2646,6 +2724,20 @@ remoteGlobalIDString = 65FB3F6609D11E9100F49DEB; remoteInfo = "Derived Sources"; }; + B70B8C003BC4F51DF41C2D65 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 65FB3F6609D11E9100F49DEB; + remoteInfo = "Derived Sources"; + }; + A269FDF04AF38423A3A5DE9A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6B03652E1F50D87F0DEC6B42; + remoteInfo = mya; + }; 44F93E102AE7200100FFA37C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -2758,6 +2850,27 @@ remoteGlobalIDString = FE533CA11F217DB30016A1FE; remoteInfo = testmasm; }; + 7E83C41C17D785F3003DC41B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 65FB3F6609D11E9100F49DEB; + remoteInfo = "Derived Sources"; + }; + 7E83C41E17D785F3003DC41B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E1AC2E2720F7B94C00B0897D; + remoteInfo = "Unlock Keychain"; + }; + 7E83C42017D785F3003DC41B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7E83C41317D785F3003DC41B; + remoteInfo = testLibJSCTools; + }; FF0F56882E33437C002A232A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -2815,6 +2928,17 @@ name = "Product Dependencies"; runOnlyForDeploymentPostprocessing = 0; }; + 184CD487A9C6C6DCE0BA2ADA /* Product Dependencies */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 16; + files = ( + ACB50B356C9AA8E90AA3DF50 /* JavaScriptCore.framework in Product Dependencies */, + ); + name = "Product Dependencies"; + runOnlyForDeploymentPostprocessing = 0; + }; 5DBB1524131D0BA10056AD36 /* Copy Support Script */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -3951,6 +4075,23 @@ 1482B74B0A43032800517CFC /* JSStringRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringRef.h; sourceTree = ""; }; 1482B74C0A43032800517CFC /* JSStringRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringRef.cpp; sourceTree = ""; }; 1482B78A0A4305AB00517CFC /* APICast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APICast.h; sourceTree = ""; }; + 55D0F2DD9CA70132D5104B34 /* CorpseProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseProcess.h; sourceTree = ""; }; + 9F41D6082A3E4B57C0768DB1 /* CorpseRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseRegion.h; sourceTree = ""; }; + 94711688984F16F71D615DE5 /* CorpseSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseSnapshot.h; sourceTree = ""; }; + 8F1FA0900D09DF06EE63F7D2 /* CorpseSymbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseSymbol.h; sourceTree = ""; }; + E8D1735B28066A3B1D756ECC /* CorpseSymbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseSymbol.cpp; sourceTree = ""; }; + 68BBF9CBD85C8635B2B8385F /* CorpseProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseProcess.cpp; sourceTree = ""; }; + C8503B7E641A29DF5B0E3742 /* CorpseRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseRegion.cpp; sourceTree = ""; }; + 5E906BE4CC29012A83A8F299 /* CorpseSnapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseSnapshot.cpp; sourceTree = ""; }; + 2C6EB9C72F84ED87DF23277A /* CorpseAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseAddress.h; sourceTree = ""; }; + 9CBE14E70FB474FCFCD6A8B9 /* CorpseClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseClient.h; sourceTree = ""; }; + 422D2FE4AA2401EA8C3F2D8F /* CorpseClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseClient.cpp; sourceTree = ""; }; + 8DDA7A78AD90B64B97AE329C /* CorpseError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseError.h; sourceTree = ""; }; + 2AC15166B6F71CD338DD8D6F /* CorpseError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseError.cpp; sourceTree = ""; }; + 7E83C43617D785F3003DC41B /* CorpseExportsTrie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseExportsTrie.cpp; sourceTree = ""; }; + 7E83C43517D785F3003DC41B /* CorpseExportsTrie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseExportsTrie.h; sourceTree = ""; }; + 211E3D6CA97F31CEB385A75A /* CorpseThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseThread.h; sourceTree = ""; }; + 960BD2B783EAEBE3233F91BF /* CorpseThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseThread.cpp; sourceTree = ""; }; 1482B7E10A43076000517CFC /* JSObjectRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectRef.h; sourceTree = ""; }; 1482B7E20A43076000517CFC /* JSObjectRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSObjectRef.cpp; sourceTree = ""; }; 148521D526EAEBDF00CC1D1A /* WasmHandlerInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WasmHandlerInfo.cpp; sourceTree = ""; }; @@ -4347,9 +4488,35 @@ 4487DB822AF825C800AFECAE /* Fuzzilli.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fuzzilli.h; sourceTree = ""; }; 44F93DFD2AE71EBD00FFA37C /* libJavaScriptCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libJavaScriptCore.xcconfig; sourceTree = ""; }; 44F93E022AE71F5400FFA37C /* libJavaScriptCore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJavaScriptCore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libJavaScriptCoreTools.xcconfig; sourceTree = ""; }; + A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TestLibJSCTools.xcconfig; sourceTree = ""; }; + 76A3C1425B4D63FC23BD2344 /* libJavaScriptCoreTools.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJavaScriptCoreTools.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7E83C42317D785F3003DC41B /* CorpseByteParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseByteParser.cpp; sourceTree = ""; }; + 7E83C42217D785F3003DC41B /* CorpseByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseByteParser.h; sourceTree = ""; }; + 7E83C42617D785F3003DC41B /* CorpseByteParserTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseByteParserTest.cpp; sourceTree = ""; }; + 7E83C42917D785F3003DC41B /* CorpseAddressTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseAddressTest.cpp; sourceTree = ""; }; + 7E83C42A17D785F3003DC41B /* CorpseAddressTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseAddressTest.h; sourceTree = ""; }; + 7E83C42C17D785F3003DC41B /* CorpseProcessTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseProcessTest.cpp; sourceTree = ""; }; + 7E83C42D17D785F3003DC41B /* CorpseProcessTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseProcessTest.h; sourceTree = ""; }; + 7E83C42F17D785F3003DC41B /* CorpseRegionTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseRegionTest.cpp; sourceTree = ""; }; + 7E83C43017D785F3003DC41B /* CorpseRegionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseRegionTest.h; sourceTree = ""; }; + 7E83C43217D785F3003DC41B /* CorpseThreadTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseThreadTest.cpp; sourceTree = ""; }; + 7E83C43317D785F3003DC41B /* CorpseThreadTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseThreadTest.h; sourceTree = ""; }; + 7E83C42517D785F3003DC41B /* CorpseByteParserTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseByteParserTest.h; sourceTree = ""; }; + 7E83C40217D785F3003DC41B /* CorpseExportsTrieTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseExportsTrieTest.cpp; sourceTree = ""; }; + 7E83C40117D785F3003DC41B /* CorpseExportsTrieTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseExportsTrieTest.h; sourceTree = ""; }; + 7E83C40417D785F3003DC41B /* LibJSCToolsTestUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LibJSCToolsTestUtilities.cpp; sourceTree = ""; }; + 7E83C40317D785F3003DC41B /* LibJSCToolsTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibJSCToolsTestUtilities.h; sourceTree = ""; }; + 7E83C40617D785F3003DC41B /* CorpseSnapshotTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseSnapshotTest.cpp; sourceTree = ""; }; + 7E83C40517D785F3003DC41B /* CorpseSnapshotTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseSnapshotTest.h; sourceTree = ""; }; + 7E83C40817D785F3003DC41B /* CorpseSymbolTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CorpseSymbolTest.cpp; sourceTree = ""; }; + 7E83C40717D785F3003DC41B /* CorpseSymbolTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CorpseSymbolTest.h; sourceTree = ""; }; + 7E83C40017D785F3003DC41B /* testLibJSCTools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testLibJSCTools.cpp; sourceTree = ""; }; + 7E83C40917D785F3003DC41B /* testLibJSCTools */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testLibJSCTools; sourceTree = BUILT_PRODUCTS_DIR; }; 44F93E0D2AE71F9F00FFA37C /* JavaScriptCoreFramework.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JavaScriptCoreFramework.cpp; sourceTree = ""; }; 451539B812DC994500EF7AC4 /* Yarr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Yarr.h; path = yarr/Yarr.h; sourceTree = ""; }; 45E12D8806A49B0F00E9DF84 /* jsc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc.cpp; sourceTree = ""; tabWidth = 4; }; + 806620AA0612E27A5093C379 /* mya.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mya.cpp; path = mya/mya.cpp; sourceTree = ""; tabWidth = 4; }; 4615E4662B5833FB001D4D53 /* WasmBBQJIT64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmBBQJIT64.h; sourceTree = ""; }; 4615E4682B5833FB001D4D53 /* WasmBBQJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmBBQJIT64.cpp; sourceTree = ""; }; 4B78E098294427D2003C6682 /* B3SIMDValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3SIMDValue.cpp; path = b3/B3SIMDValue.cpp; sourceTree = ""; }; @@ -4752,6 +4919,7 @@ 5C7E1A152DA1B0E100A4C005 /* JSTypedArrayViewPrototypeInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewPrototypeInternal.h; sourceTree = ""; }; 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = ""; }; 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = ""; }; + 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Mya.xcconfig; sourceTree = ""; }; 5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAvailability.h; sourceTree = ""; }; 623A37EB1B87A7BD00754209 /* RegisterMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterMap.h; sourceTree = ""; }; 627673211B680C1E00FD9F2E /* CallMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallMode.cpp; sourceTree = ""; }; @@ -5183,6 +5351,7 @@ 932F5BD80822A1C700736975 /* Info.plist */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; 932F5BD90822A1C700736975 /* JavaScriptCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 932F5BE10822A1C700736975 /* jsc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jsc; sourceTree = BUILT_PRODUCTS_DIR; }; + B2D6E3DABD6662589CD25896 /* mya */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mya; sourceTree = BUILT_PRODUCTS_DIR; }; 93303FE80E6A72B500786E6A /* SmallStrings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallStrings.cpp; sourceTree = ""; }; 93303FEA0E6A72C000786E6A /* SmallStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallStrings.h; sourceTree = ""; }; 933A349A038AE7C6008635CE /* Identifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = Identifier.h; sourceTree = ""; tabWidth = 8; }; @@ -6726,6 +6895,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 97663BCF9AB10EBDF8B13940 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D9BBE216687E30084BD44207 /* libedit.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FE533CA41F217DB30016A1FE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -6735,6 +6912,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 7E83C41A17D785F3003DC41B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7E83C41017D785F3003DC41B /* Foundation.framework in Frameworks */, + 7E83C40F17D785F3003DC41B /* JavaScriptCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FF0F568C2E33437C002A232A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -6747,11 +6933,65 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 7E83C41217D785F3003DC41B /* tests */ = { + isa = PBXGroup; + children = ( + 7E83C42917D785F3003DC41B /* CorpseAddressTest.cpp */, + 7E83C42A17D785F3003DC41B /* CorpseAddressTest.h */, + 7E83C42617D785F3003DC41B /* CorpseByteParserTest.cpp */, + 7E83C42517D785F3003DC41B /* CorpseByteParserTest.h */, + 7E83C40217D785F3003DC41B /* CorpseExportsTrieTest.cpp */, + 7E83C40117D785F3003DC41B /* CorpseExportsTrieTest.h */, + 7E83C42C17D785F3003DC41B /* CorpseProcessTest.cpp */, + 7E83C42D17D785F3003DC41B /* CorpseProcessTest.h */, + 7E83C42F17D785F3003DC41B /* CorpseRegionTest.cpp */, + 7E83C43017D785F3003DC41B /* CorpseRegionTest.h */, + 7E83C40617D785F3003DC41B /* CorpseSnapshotTest.cpp */, + 7E83C40517D785F3003DC41B /* CorpseSnapshotTest.h */, + 7E83C40817D785F3003DC41B /* CorpseSymbolTest.cpp */, + 7E83C40717D785F3003DC41B /* CorpseSymbolTest.h */, + 7E83C43217D785F3003DC41B /* CorpseThreadTest.cpp */, + 7E83C43317D785F3003DC41B /* CorpseThreadTest.h */, + 7E83C40417D785F3003DC41B /* LibJSCToolsTestUtilities.cpp */, + 7E83C40317D785F3003DC41B /* LibJSCToolsTestUtilities.h */, + 7E83C40017D785F3003DC41B /* testLibJSCTools.cpp */, + ); + path = tests; + sourceTree = ""; + }; + 65036098A29083DFB9FCF27C /* corpse */ = { + isa = PBXGroup; + children = ( + 7E83C41217D785F3003DC41B /* tests */, + 2C6EB9C72F84ED87DF23277A /* CorpseAddress.h */, + 7E83C42317D785F3003DC41B /* CorpseByteParser.cpp */, + 7E83C42217D785F3003DC41B /* CorpseByteParser.h */, + 422D2FE4AA2401EA8C3F2D8F /* CorpseClient.cpp */, + 9CBE14E70FB474FCFCD6A8B9 /* CorpseClient.h */, + 2AC15166B6F71CD338DD8D6F /* CorpseError.cpp */, + 8DDA7A78AD90B64B97AE329C /* CorpseError.h */, + 7E83C43617D785F3003DC41B /* CorpseExportsTrie.cpp */, + 7E83C43517D785F3003DC41B /* CorpseExportsTrie.h */, + 68BBF9CBD85C8635B2B8385F /* CorpseProcess.cpp */, + 55D0F2DD9CA70132D5104B34 /* CorpseProcess.h */, + C8503B7E641A29DF5B0E3742 /* CorpseRegion.cpp */, + 9F41D6082A3E4B57C0768DB1 /* CorpseRegion.h */, + 5E906BE4CC29012A83A8F299 /* CorpseSnapshot.cpp */, + 94711688984F16F71D615DE5 /* CorpseSnapshot.h */, + E8D1735B28066A3B1D756ECC /* CorpseSymbol.cpp */, + 8F1FA0900D09DF06EE63F7D2 /* CorpseSymbol.h */, + 960BD2B783EAEBE3233F91BF /* CorpseThread.cpp */, + 211E3D6CA97F31CEB385A75A /* CorpseThread.h */, + ); + path = corpse; + sourceTree = ""; + }; 034768DFFF38A50411DB9C8B /* Products */ = { isa = PBXGroup; children = ( 0F9327591C20BCBA00CF6564 /* dynbench */, 932F5BE10822A1C700736975 /* jsc */, + B2D6E3DABD6662589CD25896 /* mya */, 0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */, 14BD688E215191310050DAFF /* JSCLLIntSettingsExtractor */, 141211200A48793C00480255 /* minidom */, @@ -6761,9 +7001,11 @@ 52CD0F642242F569004A18A5 /* testdfg */, FE533CAC1F217DB40016A1FE /* testmasm */, 79281BDC20B62B3E002E2A60 /* testmem */, + 7E83C40917D785F3003DC41B /* testLibJSCTools */, 6511230514046A4C002B101D /* testRegExp */, 932F5BD90822A1C700736975 /* JavaScriptCore.framework */, 44F93E022AE71F5400FFA37C /* libJavaScriptCore.a */, + 76A3C1425B4D63FC23BD2344 /* libJavaScriptCoreTools.a */, FF0F56942E33437C002A232A /* testwasmdebugger */, ); name = Products; @@ -6795,6 +7037,7 @@ 44F93E0D2AE71F9F00FFA37C /* JavaScriptCoreFramework.cpp */, F5C290E60284F98E018635CA /* JavaScriptCorePrefix.h */, 45E12D8806A49B0F00E9DF84 /* jsc.cpp */, + 806620AA0612E27A5093C379 /* mya.cpp */, A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */, 79D7B0E121152FD200FE7C64 /* entitlements.plist */, 53ADF4742F0D7A2000A05CDD /* lol */, @@ -6804,6 +7047,7 @@ A7D8019F1880D66E0026C39B /* builtins */, 969A078F0ED1D3AE00F1F681 /* bytecode */, 7E39D81D0EC38EFA003AF11A /* bytecompiler */, + 65036098A29083DFB9FCF27C /* corpse */, 1C90513E0BA9E8830081E9D0 /* Configurations */, 1480DB9A0DDC2231003CFDF2 /* debugger */, 650FDF8D09D0FCA700769E54 /* Derived Sources */, @@ -7952,8 +8196,11 @@ 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */, 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */, 44F93DFD2AE71EBD00FFA37C /* libJavaScriptCore.xcconfig */, + 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */, DD8A31502F17A00000000001 /* LLIntExtractor.xcconfig */, + 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */, FEE0A12229FE250400CED5E4 /* TestExecutable.xcconfig */, + A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */, BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */, ); path = Configurations; @@ -11438,6 +11685,16 @@ E3FCCB642310A90D00238E72 /* ConstructorKind.h in Headers */, A57D23F21891B5B40031C7FA /* ContentSearchUtilities.h in Headers */, 52678F911A04177C006A306D /* ControlFlowProfiler.h in Headers */, + 725D045D67B3017EAC56561C /* CorpseAddress.h in Headers */, + 7E83C42817D785F3003DC41B /* CorpseByteParser.h in Headers */, + 80B96670131FB9EBB9AD49CC /* CorpseClient.h in Headers */, + 85428E7BE0B3557DD2988043 /* CorpseError.h in Headers */, + 7E83C43717D785F3003DC41B /* CorpseExportsTrie.h in Headers */, + 0D9C2E68ACFF010D91916993 /* CorpseProcess.h in Headers */, + 3A7C1E5D9B0F4A2681C34D07 /* CorpseRegion.h in Headers */, + CA47D093D003440A28D15924 /* CorpseSnapshot.h in Headers */, + 5601486802533982ACC870BE /* CorpseSymbol.h in Headers */, + 56C6C2B7EBDCC63B6ECEA9AD /* CorpseThread.h in Headers */, C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */, C4F4B6F31A05C944005CAB76 /* cpp_generator_templates.py in Headers */, 0F30D7C01D95D6320053089D /* CPU.h in Headers */, @@ -13005,6 +13262,22 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 49D9C56EC7911960C24239F3 /* JavaScriptCoreTools */ = { + isa = PBXNativeTarget; + buildConfigurationList = CDAB8A13AA6F0C8A7D95A0DD /* Build configuration list for PBXNativeTarget "JavaScriptCoreTools" */; + buildPhases = ( + 0F73B81D27D8B848DDFD4BA2 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + A1B2C3000BE5B4A700C0FFEE /* PBXTargetDependency */, + ); + name = JavaScriptCoreTools; + productName = JavaScriptCoreTools; + productReference = 76A3C1425B4D63FC23BD2344 /* libJavaScriptCoreTools.a */; + productType = "com.apple.product-type.library.static"; + }; 0F6183381C45F62A0072450B /* testair */ = { isa = PBXNativeTarget; buildConfigurationList = 0F61833E1C45F62A0072450B /* Build configuration list for PBXNativeTarget "testair" */; @@ -13261,6 +13534,9 @@ buildRules = ( ); dependencies = ( + A1B2C30005E5B4A700C0FFEE /* PBXTargetDependency */, + A1B2C30007E5B4A700C0FFEE /* PBXTargetDependency */, + A1B2C30009E5B4A700C0FFEE /* PBXTargetDependency */, 14D9D9DA218462B5009126C2 /* PBXTargetDependency */, ); name = jsc; @@ -13269,6 +13545,27 @@ productReference = 932F5BE10822A1C700736975 /* jsc */; productType = "com.apple.product-type.tool"; }; + 6B03652E1F50D87F0DEC6B42 /* mya */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1564F766F55B0B045D183322 /* Build configuration list for PBXNativeTarget "mya" */; + buildPhases = ( + 184CD487A9C6C6DCE0BA2ADA /* Product Dependencies */, + FE35E0580C774FF6AC63188E /* Generate Entitlements */, + 4ECC923BDB875C54F15ECFB7 /* Sources */, + 97663BCF9AB10EBDF8B13940 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + D3934A4385F631C04057F7E7 /* PBXTargetDependency */, + 87B6EB7D11A4B965B9269538 /* PBXTargetDependency */, + ); + name = mya; + productInstallPath = /usr/local/bin; + productName = mya; + productReference = B2D6E3DABD6662589CD25896 /* mya */; + productType = "com.apple.product-type.tool"; + }; FE533CA11F217DB30016A1FE /* testmasm */ = { isa = PBXNativeTarget; buildConfigurationList = FE533CA71F217DB30016A1FE /* Build configuration list for PBXNativeTarget "testmasm" */; @@ -13287,6 +13584,27 @@ productReference = FE533CAC1F217DB40016A1FE /* testmasm */; productType = "com.apple.product-type.tool"; }; + 7E83C41317D785F3003DC41B /* testLibJSCTools */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7E83C41417D785F3003DC41B /* Build configuration list for PBXNativeTarget "testLibJSCTools" */; + buildPhases = ( + 7E83C42117D785F3003DC41B /* Generate Entitlements */, + 7E83C41917D785F3003DC41B /* Sources */, + 7E83C41A17D785F3003DC41B /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + F7DDEC2D6CAFD2ACDD19D991 /* PBXTargetDependency */, + 7E83C41B17D785F3003DC41B /* PBXTargetDependency */, + 7E83C41D17D785F3003DC41B /* PBXTargetDependency */, + ); + name = testLibJSCTools; + productInstallPath = /usr/local/bin; + productName = testLibJSCTools; + productReference = 7E83C40917D785F3003DC41B /* testLibJSCTools */; + productType = "com.apple.product-type.tool"; + }; FF0F56862E33437C002A232A /* testwasmdebugger */ = { isa = PBXNativeTarget; buildConfigurationList = FF0F568F2E33437C002A232A /* Build configuration list for PBXNativeTarget "testwasmdebugger" */; @@ -13354,6 +13672,8 @@ 1412111F0A48793C00480255 /* minidom */, 14BD59BE0A3E8F9000BAF59C /* testapi */, 932F5BDA0822A1C700736975 /* jsc */, + 49D9C56EC7911960C24239F3 /* JavaScriptCoreTools */, + 6B03652E1F50D87F0DEC6B42 /* mya */, 651122F714046A4C002B101D /* testRegExp */, 0FEC85941BDB5CF10080FF74 /* testb3 */, 5D6B2A47152B9E17005231DE /* Test Tools */, @@ -13364,6 +13684,7 @@ 5325BDBF21DFF2B100A0DEE1 /* Apply Configuration to XCFileLists */, 52CD0F592242F569004A18A5 /* testdfg */, FF0F56862E33437C002A232A /* testwasmdebugger */, + 7E83C41317D785F3003DC41B /* testLibJSCTools */, ); }; /* End PBXProject section */ @@ -13772,6 +14093,26 @@ shellPath = /bin/sh; shellScript = "Scripts/process-entitlements.sh\n"; }; + FE35E0580C774FF6AC63188E /* Generate Entitlements */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Scripts/process-entitlements.sh", + ); + name = "Generate Entitlements"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(WK_PROCESSED_XCENT_FILE)", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "Scripts/process-entitlements.sh\n"; + }; E3D6F6EE25D78CF600C20EB4 /* Generate Entitlements */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -13976,6 +14317,26 @@ shellPath = /bin/sh; shellScript = "Scripts/process-entitlements.sh\n"; }; + 7E83C42117D785F3003DC41B /* Generate Entitlements */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Scripts/process-entitlements.sh", + ); + name = "Generate Entitlements"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(WK_PROCESSED_XCENT_FILE)", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "Scripts/process-entitlements.sh\n"; + }; FF0F56892E33437C002A232A /* Generate Entitlements */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -13999,6 +14360,22 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0F73B81D27D8B848DDFD4BA2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7E83C42417D785F3003DC41B /* CorpseByteParser.cpp in Sources */, + C2EB941F3198AE0BD86A2324 /* CorpseClient.cpp in Sources */, + 121D90BB8171A66F1922D548 /* CorpseError.cpp in Sources */, + 7E83C43817D785F3003DC41B /* CorpseExportsTrie.cpp in Sources */, + C366EA5039A3B51405995EA6 /* CorpseProcess.cpp in Sources */, + 5E2B94A17C6D40F3B85219CE /* CorpseRegion.cpp in Sources */, + 0946712DEC51E0E86C4A49E3 /* CorpseSnapshot.cpp in Sources */, + 377C8C2416AE3DF90650C0E9 /* CorpseSymbol.cpp in Sources */, + EF648B9EEAF54C44048B416A /* CorpseThread.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 0F6183391C45F62A0072450B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -14345,6 +14722,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4ECC923BDB875C54F15ECFB7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6DCC8B386903B87B8A4E5A26 /* mya.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FE533CA21F217DB30016A1FE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -14353,6 +14738,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 7E83C41917D785F3003DC41B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7E83C42B17D785F3003DC41B /* CorpseAddressTest.cpp in Sources */, + 7E83C42717D785F3003DC41B /* CorpseByteParserTest.cpp in Sources */, + 7E83C40B17D785F3003DC41B /* CorpseExportsTrieTest.cpp in Sources */, + 7E83C42E17D785F3003DC41B /* CorpseProcessTest.cpp in Sources */, + 7E83C43117D785F3003DC41B /* CorpseRegionTest.cpp in Sources */, + 7E83C40D17D785F3003DC41B /* CorpseSnapshotTest.cpp in Sources */, + 7E83C40E17D785F3003DC41B /* CorpseSymbolTest.cpp in Sources */, + 7E83C43417D785F3003DC41B /* CorpseThreadTest.cpp in Sources */, + 7E83C40C17D785F3003DC41B /* LibJSCToolsTestUtilities.cpp in Sources */, + 7E83C40A17D785F3003DC41B /* testLibJSCTools.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FF0F568A2E33437C002A232A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -14377,6 +14779,31 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + D3934A4385F631C04057F7E7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 49D9C56EC7911960C24239F3 /* JavaScriptCoreTools */; + targetProxy = 6044D4B120B01FBCA9BCFBE5 /* PBXContainerItemProxy */; + }; + A1B2C30005E5B4A700C0FFEE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 49D9C56EC7911960C24239F3 /* JavaScriptCoreTools */; + targetProxy = A1B2C30004E5B4A700C0FFEE /* PBXContainerItemProxy */; + }; + A1B2C30007E5B4A700C0FFEE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6B03652E1F50D87F0DEC6B42 /* mya */; + targetProxy = A1B2C30006E5B4A700C0FFEE /* PBXContainerItemProxy */; + }; + A1B2C30009E5B4A700C0FFEE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7E83C41317D785F3003DC41B /* testLibJSCTools */; + targetProxy = A1B2C30008E5B4A700C0FFEE /* PBXContainerItemProxy */; + }; + F7DDEC2D6CAFD2ACDD19D991 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 49D9C56EC7911960C24239F3 /* JavaScriptCoreTools */; + targetProxy = 291A8D565940996D3CA021C1 /* PBXContainerItemProxy */; + }; 074D7E0A2E3D3B6800CD38C6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; @@ -14462,6 +14889,21 @@ target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; targetProxy = 14D9D9D9218462B5009126C2 /* PBXContainerItemProxy */; }; + 87B6EB7D11A4B965B9269538 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; + targetProxy = B70B8C003BC4F51DF41C2D65 /* PBXContainerItemProxy */; + }; + A1B2C3000BE5B4A700C0FFEE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; + targetProxy = A1B2C3000AE5B4A700C0FFEE /* PBXContainerItemProxy */; + }; + 5F40739EF054554602787C41 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6B03652E1F50D87F0DEC6B42 /* mya */; + targetProxy = A269FDF04AF38423A3A5DE9A /* PBXContainerItemProxy */; + }; 44F93E112AE7200100FFA37C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 44F93E012AE71F5300FFA37C /* libJavaScriptCore */; @@ -14542,6 +14984,21 @@ target = FE533CA11F217DB30016A1FE /* testmasm */; targetProxy = FE533CAE1F217EC60016A1FE /* PBXContainerItemProxy */; }; + 7E83C41B17D785F3003DC41B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; + targetProxy = 7E83C41C17D785F3003DC41B /* PBXContainerItemProxy */; + }; + 7E83C41D17D785F3003DC41B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E1AC2E2720F7B94C00B0897D /* Unlock Keychain */; + targetProxy = 7E83C41E17D785F3003DC41B /* PBXContainerItemProxy */; + }; + 7E83C41F17D785F3003DC41B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7E83C41317D785F3003DC41B /* testLibJSCTools */; + targetProxy = 7E83C42017D785F3003DC41B /* PBXContainerItemProxy */; + }; FF0F56872E33437C002A232A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E1AC2E2720F7B94C00B0897D /* Unlock Keychain */; @@ -14555,6 +15012,34 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 0496C9FAB31F908B0425279C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + CF17CD764111B2A78C3D8F10 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 1738026904B5B9E1BA357B8F /* Profiling */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */; + buildSettings = { + }; + name = Profiling; + }; + 1A9B847BE318F847F08771D9 /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33CCFE0660BE540320EF4777 /* libJavaScriptCoreTools.xcconfig */; + buildSettings = { + }; + name = Production; + }; 0F61833F1C45F62A0072450B /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = FEE0A12229FE250400CED5E4 /* TestExecutable.xcconfig */; @@ -14731,6 +15216,34 @@ }; name = Production; }; + 0D9FBE8C4B6D65ED3E83AB12 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 39672BABA758BF6EC3C9BDE6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */; + buildSettings = { + }; + name = Release; + }; + D433E29BE1849C8E3DEEF0BB /* Profiling */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */; + buildSettings = { + }; + name = Profiling; + }; + 9FAFBEC1CDCCB2F48A335C3E /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E812A1EEBE0D5AEA7D3C74B /* Mya.xcconfig */; + buildSettings = { + }; + name = Production; + }; 149C276D08902AFE008A9EFC /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */; @@ -15183,6 +15696,38 @@ }; name = Production; }; + 7E83C41517D785F3003DC41B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 7E83C41617D785F3003DC41B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 7E83C41717D785F3003DC41B /* Profiling */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profiling; + }; + 7E83C41817D785F3003DC41B /* Production */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1B2C30001E5B4A700C0FFEE /* TestLibJSCTools.xcconfig */; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Production; + }; FF0F56902E33437C002A232A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = FEE0A12229FE250400CED5E4 /* TestExecutable.xcconfig */; @@ -15218,6 +15763,17 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + CDAB8A13AA6F0C8A7D95A0DD /* Build configuration list for PBXNativeTarget "JavaScriptCoreTools" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0496C9FAB31F908B0425279C /* Debug */, + CF17CD764111B2A78C3D8F10 /* Release */, + 1738026904B5B9E1BA357B8F /* Profiling */, + 1A9B847BE318F847F08771D9 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; 0F61833E1C45F62A0072450B /* Build configuration list for PBXNativeTarget "testair" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -15295,6 +15851,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; + 1564F766F55B0B045D183322 /* Build configuration list for PBXNativeTarget "mya" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0D9FBE8C4B6D65ED3E83AB12 /* Debug */, + 39672BABA758BF6EC3C9BDE6 /* Release */, + D433E29BE1849C8E3DEEF0BB /* Profiling */, + 9FAFBEC1CDCCB2F48A335C3E /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; 149C276C08902AFE008A9EFC /* Build configuration list for PBXAggregateTarget "All" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -15449,6 +16016,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; + 7E83C41417D785F3003DC41B /* Build configuration list for PBXNativeTarget "testLibJSCTools" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7E83C41517D785F3003DC41B /* Debug */, + 7E83C41617D785F3003DC41B /* Release */, + 7E83C41717D785F3003DC41B /* Profiling */, + 7E83C41817D785F3003DC41B /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; FF0F568F2E33437C002A232A /* Build configuration list for PBXNativeTarget "testwasmdebugger" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Source/JavaScriptCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations b/Source/JavaScriptCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations index 18aeede54748..4d1e59f20fbf 100644 --- a/Source/JavaScriptCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations +++ b/Source/JavaScriptCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations @@ -71,14 +71,10 @@ inspector/ConsoleMessage.cpp inspector/JSGlobalObjectInspectorController.cpp inspector/JSJavaScriptCallFrame.cpp inspector/ScriptCallStack.cpp -inspector/agents/InspectorAgent.cpp -inspector/agents/InspectorAuditAgent.cpp -inspector/agents/InspectorConsoleAgent.cpp inspector/agents/InspectorDebuggerAgent.cpp inspector/agents/InspectorHeapAgent.cpp inspector/agents/InspectorRuntimeAgent.cpp inspector/agents/InspectorScriptProfilerAgent.cpp -inspector/agents/JSGlobalObjectRuntimeAgent.cpp jit/BaselineJITPlan.cpp jit/ExecutableAllocator.cpp jit/GCAwareJITStubRoutine.cpp diff --git a/Source/JavaScriptCore/SaferCPPExpectations/UncountedLambdaCapturesCheckerExpectations b/Source/JavaScriptCore/SaferCPPExpectations/UncountedLambdaCapturesCheckerExpectations index 3a64d3fc500c..2d708615bb1b 100644 --- a/Source/JavaScriptCore/SaferCPPExpectations/UncountedLambdaCapturesCheckerExpectations +++ b/Source/JavaScriptCore/SaferCPPExpectations/UncountedLambdaCapturesCheckerExpectations @@ -3,7 +3,6 @@ bytecode/InlineCacheCompiler.cpp bytecode/ObjectPropertyConditionSet.cpp bytecompiler/NodesCodegen.cpp debugger/Debugger.cpp -dfg/DFGDesiredWatchpoints.h dfg/DFGLazyJSValue.cpp dfg/DFGObjectAllocationSinkingPhase.cpp ftl/FTLCompile.cpp diff --git a/Source/JavaScriptCore/Scripts/process-entitlements.sh b/Source/JavaScriptCore/Scripts/process-entitlements.sh index ff396dcd52c6..8e8c00f5d4ff 100755 --- a/Source/JavaScriptCore/Scripts/process-entitlements.sh +++ b/Source/JavaScriptCore/Scripts/process-entitlements.sh @@ -69,6 +69,23 @@ function mac_process_testapi_entitlements() fi } +function mac_process_mya_entitlements() +{ + if [[ "${WK_USE_RESTRICTED_ENTITLEMENTS}" == YES ]] + then + plistbuddy Add :com.apple.private.cs.debugger bool YES + + if [[ "${WK_USE_FATAL_EXCEPTIONS}" == YES ]] + then + plistbuddy Add :com.apple.private.pac.exception bool YES + fi + + plistbuddy Add :com.apple.developer.kernel.extended-virtual-addressing bool YES + + plistbuddy Add :com.apple.developer.hardened-process bool YES + fi +} + # ======================================== # macCatalyst entitlements # ======================================== @@ -133,6 +150,23 @@ function maccatalyst_process_testapi_entitlements() fi } +function maccatalyst_process_mya_entitlements() +{ + if [[ "${WK_USE_RESTRICTED_ENTITLEMENTS}" == YES ]] + then + plistbuddy Add :com.apple.private.cs.debugger bool YES + + if [[ "${WK_USE_FATAL_EXCEPTIONS}" == YES ]] + then + plistbuddy Add :com.apple.private.pac.exception bool YES + fi + + plistbuddy Add :com.apple.developer.kernel.extended-virtual-addressing bool YES + + plistbuddy Add :com.apple.developer.hardened-process bool YES + fi +} + # ======================================== # iOS Family entitlements # ======================================== @@ -165,6 +199,22 @@ function ios_family_process_jsc_entitlements() plistbuddy Add :com.apple.developer.hardened-process bool YES } +function ios_family_process_mya_entitlements() +{ + if [[ "${WK_USE_RESTRICTED_ENTITLEMENTS}" == YES ]] + then + plistbuddy Add :com.apple.private.cs.debugger bool YES + fi + + if [[ "${WK_USE_FATAL_EXCEPTIONS}" == YES ]] + then + plistbuddy Add :com.apple.private.pac.exception bool YES + fi + + plistbuddy Add :com.apple.developer.kernel.extended-virtual-addressing bool YES + plistbuddy Add :com.apple.developer.hardened-process bool YES +} + rm -f "${WK_PROCESSED_XCENT_FILE}" plistbuddy Clear dict @@ -185,6 +235,9 @@ then "${PRODUCT_NAME}" == testmem || "${PRODUCT_NAME}" == testRegExp ]]; then mac_process_jsc_entitlements elif [[ "${PRODUCT_NAME}" == testapi ]]; then mac_process_testapi_entitlements + elif [[ "${PRODUCT_NAME}" == mya ]]; then mac_process_mya_entitlements + # testLibJSCTools only ever snapshots its own process, which needs no entitlement. + elif [[ "${PRODUCT_NAME}" == testLibJSCTools ]]; then true else echo "Unsupported/unknown product: ${PRODUCT_NAME}" fi elif [[ "${WK_PLATFORM_NAME}" == maccatalyst || "${WK_PLATFORM_NAME}" == iosmac ]] @@ -201,6 +254,9 @@ then "${PRODUCT_NAME}" == testmem || "${PRODUCT_NAME}" == testRegExp ]]; then maccatalyst_process_jsc_entitlements elif [[ "${PRODUCT_NAME}" == testapi ]]; then maccatalyst_process_testapi_entitlements + elif [[ "${PRODUCT_NAME}" == mya ]]; then maccatalyst_process_mya_entitlements + # testLibJSCTools only ever snapshots its own process, which needs no entitlement. + elif [[ "${PRODUCT_NAME}" == testLibJSCTools ]]; then true else echo "Unsupported/unknown product: ${PRODUCT_NAME}" fi elif [[ "${WK_PLATFORM_NAME}" == iphoneos || @@ -218,6 +274,9 @@ then "${PRODUCT_NAME}" == testmasm || "${PRODUCT_NAME}" == testmem || "${PRODUCT_NAME}" == testRegExp ]]; then ios_family_process_jsc_entitlements + elif [[ "${PRODUCT_NAME}" == mya ]]; then ios_family_process_mya_entitlements + # testLibJSCTools only ever snapshots its own process, which needs no entitlement. + elif [[ "${PRODUCT_NAME}" == testLibJSCTools ]]; then true else echo "Unsupported/unknown product: ${PRODUCT_NAME}" fi else diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h index 17088a7e5f51..debe749bfa00 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h @@ -191,10 +191,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - zeroExtend32ToWord(src, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) @@ -326,10 +322,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void add64(TrustedImm32 imm, RegisterID src, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - move(src, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) @@ -360,10 +352,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void add64(TrustedImm64 imm, RegisterID src, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - move(src, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) @@ -1515,10 +1503,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void sub32(RegisterID left, TrustedImm32 imm, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - zeroExtend32ToWord(left, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) @@ -1591,10 +1575,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void sub64(RegisterID left, TrustedImm32 imm, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - move(left, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) @@ -1615,10 +1595,6 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler { void sub64(RegisterID left, TrustedImm64 imm, RegisterID dest) { auto immediate = imm.m_value; - if (!immediate) { - move(left, dest); - return; - } if (auto tuple = tryExtractShiftedImm(immediate)) { auto [u12, shift, inverted] = tuple.value(); if (!inverted) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h index f3523d36cd71..67975043b8cb 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h @@ -5122,9 +5122,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void add64(TrustedImm32 imm, RegisterID srcDest) { - if (!imm.m_value) - return; - if (imm.m_value == 1) m_assembler.incq_r(srcDest); else @@ -5133,9 +5130,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void add64(TrustedImm64 imm, RegisterID dest) { - if (!imm.m_value) - return; - if (imm.m_value == 1) m_assembler.incq_r(dest); else { @@ -5146,21 +5140,11 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void add64(TrustedImm32 imm, RegisterID src, RegisterID dest) { - if (!imm.m_value) { - move(src, dest); - return; - } - m_assembler.leaq_mr(imm.m_value, src, dest); } void add64(TrustedImm64 imm, RegisterID src, RegisterID dest) { - if (!imm.m_value) { - move(src, dest); - return; - } - if (WTF::isRepresentableAs(imm.m_value)) m_assembler.leaq_mr(imm.m_value, src, dest); else { @@ -5801,9 +5785,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void sub64(TrustedImm32 imm, RegisterID dest) { - if (!imm.m_value) - return; - if (imm.m_value == 1) m_assembler.decq_r(dest); else @@ -5812,11 +5793,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void sub64(RegisterID a, TrustedImm32 imm, RegisterID dest) { - if (!imm.m_value) { - move(a, dest); - return; - } - if (a == dest) { sub64(imm, dest); return; @@ -5831,9 +5807,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void sub64(TrustedImm64 imm, RegisterID dest) { - if (!imm.m_value) - return; - if (imm.m_value == 1) m_assembler.decq_r(dest); else { @@ -5844,11 +5817,6 @@ class MacroAssemblerX86_64 : public AbstractMacroAssembler { void sub64(RegisterID src, TrustedImm64 imm, RegisterID dest) { - if (!imm.m_value) { - move(src, dest); - return; - } - if (src == dest) { sub64(imm, dest); return; diff --git a/Source/JavaScriptCore/assembler/testmasm.cpp b/Source/JavaScriptCore/assembler/testmasm.cpp index 3f495628f492..4c586c98d871 100644 --- a/Source/JavaScriptCore/assembler/testmasm.cpp +++ b/Source/JavaScriptCore/assembler/testmasm.cpp @@ -975,216 +975,6 @@ void testStore64Imm64AddressPointer() doTest(0xAAAA432198765555); } -void testAdd32Imm() -{ - for (auto immediate : int32Operands()) { - for (auto immediate2 : int32Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm32(immediate), GPRInfo::returnValueGPR); - jit.add32(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(add), static_cast(immediate) + static_cast(immediate2)); - } - } -} - -void testAdd32ArgImm() -{ - for (auto immediate : int32Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.add32(CCallHelpers::TrustedImm32(immediate), GPRInfo::argumentGPR0, GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value : int32Operands()) - CHECK_EQ(invoke(add, value), static_cast(value) + static_cast(immediate)); - } -} - -void testAdd64Imm32() -{ - for (auto immediate : int64Operands()) { - for (auto immediate2 : int32Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); - jit.add64(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(add), static_cast(immediate) + static_cast(immediate2)); - } - } -} - -void testAdd64ArgImm32() -{ - for (auto immediate : int32Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.add64(CCallHelpers::TrustedImm32(immediate), GPRInfo::argumentGPR0, GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value : int64Operands()) - CHECK_EQ(invoke(add, value), static_cast(value) + static_cast(immediate)); - } -} - -void testAdd64Imm64() -{ - for (auto immediate : int64Operands()) { - for (auto immediate2 : int64Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); - jit.add64(CCallHelpers::TrustedImm64(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(add), static_cast(immediate) + static_cast(immediate2)); - } - } -} - -void testAdd64ArgImm64() -{ - for (auto immediate : int64Operands()) { - auto add = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.add64(CCallHelpers::TrustedImm64(immediate), GPRInfo::argumentGPR0, GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value : int64Operands()) - CHECK_EQ(invoke(add, value), static_cast(value) + static_cast(immediate)); - } -} - -void testSub32Args() -{ - for (auto value : int32Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.sub32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value2 : int32Operands()) - CHECK_EQ(invoke(sub, value, value2), static_cast(value - value2)); - } -} - -void testSub32Imm() -{ - for (auto immediate : int32Operands()) { - for (auto immediate2 : int32Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm32(immediate), GPRInfo::returnValueGPR); - jit.sub32(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); - } - } -} - -void testSub64Imm32() -{ - for (auto immediate : int64Operands()) { - for (auto immediate2 : int32Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); - jit.sub64(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); - } - } -} - -void testSub64ArgImm32() -{ - for (auto immediate : int32Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.sub64(GPRInfo::argumentGPR0, CCallHelpers::TrustedImm32(immediate), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value : int64Operands()) - CHECK_EQ(invoke(sub, value), static_cast(value - immediate)); - } -} - -void testSub64Imm64() -{ - for (auto immediate : int64Operands()) { - for (auto immediate2 : int64Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); - jit.sub64(CCallHelpers::TrustedImm64(immediate2), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); - } - } -} - -void testSub64ArgImm64() -{ - for (auto immediate : int64Operands()) { - auto sub = compile([=] (CCallHelpers& jit) { - emitFunctionPrologue(jit); - - jit.sub64(GPRInfo::argumentGPR0, CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); - - emitFunctionEpilogue(jit); - jit.ret(); - }); - - for (auto value : int64Operands()) - CHECK_EQ(invoke(sub, value), static_cast(value - immediate)); - } -} - #endif // CPU(X86_64) || CPU(ARM64) void testCompareDouble(MacroAssembler::DoubleCondition condition) @@ -1435,6 +1225,111 @@ void testMultiplyAddZeroExtend32() } } +void testSub32Args() +{ + for (auto value : int32Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.sub32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + + for (auto value2 : int32Operands()) + CHECK_EQ(invoke(sub, value, value2), static_cast(value - value2)); + } +} + +void testSub32Imm() +{ + for (auto immediate : int32Operands()) { + for (auto immediate2 : int32Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.move(CCallHelpers::TrustedImm32(immediate), GPRInfo::returnValueGPR); + jit.sub32(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); + } + } +} + +void testSub64Imm32() +{ + for (auto immediate : int64Operands()) { + for (auto immediate2 : int32Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); + jit.sub64(CCallHelpers::TrustedImm32(immediate2), GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); + } + } +} + +void testSub64ArgImm32() +{ + for (auto immediate : int32Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.sub64(GPRInfo::argumentGPR0, CCallHelpers::TrustedImm32(immediate), GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + + for (auto value : int64Operands()) + CHECK_EQ(invoke(sub, value), static_cast(value - immediate)); + } +} + +void testSub64Imm64() +{ + for (auto immediate : int64Operands()) { + for (auto immediate2 : int64Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.move(CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); + jit.sub64(CCallHelpers::TrustedImm64(immediate2), GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + CHECK_EQ(invoke(sub), static_cast(immediate - immediate2)); + } + } +} + +void testSub64ArgImm64() +{ + for (auto immediate : int64Operands()) { + auto sub = compile([=] (CCallHelpers& jit) { + emitFunctionPrologue(jit); + + jit.sub64(GPRInfo::argumentGPR0, CCallHelpers::TrustedImm64(immediate), GPRInfo::returnValueGPR); + + emitFunctionEpilogue(jit); + jit.ret(); + }); + + for (auto value : int64Operands()) + CHECK_EQ(invoke(sub, value), static_cast(value - immediate)); + } +} + void testMultiplySubSignExtend32() { // d = a - SExt32(n) * SExt32(m) @@ -8530,21 +8425,6 @@ void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS RUN(testCountTrailingZeros64WithoutNullCheck()); RUN(testShiftAndAdd()); RUN(testStore64Imm64AddressPointer()); - - RUN(testAdd32Imm()); - RUN(testAdd32ArgImm()); - RUN(testAdd64Imm32()); - RUN(testAdd64ArgImm32()); - RUN(testAdd64Imm64()); - RUN(testAdd64ArgImm64()); - - RUN(testSub32Args()); - RUN(testSub32Imm()); - RUN(testSub64Imm32()); - RUN(testSub64ArgImm32()); - RUN(testSub64Imm64()); - RUN(testSub64ArgImm64()); - #endif RUN(testLoadAcq8SignedExtendTo32_Address_RegisterID()); @@ -8580,6 +8460,13 @@ void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS RUN(testMultiplySignExtend32()); RUN(testMultiplyZeroExtend32()); + RUN(testSub32Args()); + RUN(testSub32Imm()); + RUN(testSub64Imm32()); + RUN(testSub64ArgImm32()); + RUN(testSub64Imm64()); + RUN(testSub64ArgImm64()); + RUN(testMultiplyAddSignExtend32()); RUN(testMultiplyAddZeroExtend32()); RUN(testMultiplySubSignExtend32()); diff --git a/Source/JavaScriptCore/b3/B3AbstractHeapRepository.h b/Source/JavaScriptCore/b3/B3AbstractHeapRepository.h index c38f2302d2b7..79b06bedc113 100644 --- a/Source/JavaScriptCore/b3/B3AbstractHeapRepository.h +++ b/Source/JavaScriptCore/b3/B3AbstractHeapRepository.h @@ -270,6 +270,7 @@ namespace JSC::B3 { macro(JSWebAssemblyInstance_gcObjectStructureIDs) \ macro(JSWebAssemblyInstance_importFunctionStubs) \ macro(JSWebAssemblyInstance_tables) \ + macro(JSWebAssemblyInstance_functionWrappers) \ // This class is meant to be cacheable between compilations, but it doesn't have to be. // Doing so saves on creation of nodes. But clearing it will save memory. diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h index 807c8e39a576..6b57f404a6e3 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.h +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -25,7 +25,6 @@ #pragma once -#include "ConcurrentJSLock.h" #include "Structure.h" #include @@ -228,9 +227,9 @@ class ArrayProfile { static constexpr uint64_t s_smallTypedArrayMaxLength = std::numeric_limits::max(); void setMayBeLargeTypedArray() { m_arrayProfileFlags.add(ArrayProfileFlag::MayBeLargeTypedArray); } - bool mayBeLargeTypedArray(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeLargeTypedArray); } + bool mayBeLargeTypedArray() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeLargeTypedArray); } - bool mayBeResizableOrGrowableSharedTypedArray(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeResizableOrGrowableSharedTypedArray); } + bool mayBeResizableOrGrowableSharedTypedArray() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeResizableOrGrowableSharedTypedArray); } StructureID* addressOfSpeculationFailureStructureID() LIFETIME_BOUND { return &m_speculationFailureStructureID; } ArrayModes* addressOfArrayModes() LIFETIME_BOUND { return &m_observedArrayModes; } @@ -252,15 +251,15 @@ class ArrayProfile { void observeArrayMode(ArrayModes mode) { m_observedArrayModes |= mode; } void NODELETE observeIndexedRead(JSCell*, unsigned index); - ArrayModes observedArrayModes(const ConcurrentJSLocker&) const { return m_observedArrayModes; } - bool mayInterceptIndexedAccesses(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayInterceptIndexedAccesses);; } - - bool mayStoreToHole(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayStoreHole); } - bool outOfBounds(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::OutOfBounds); } - - bool usesOriginalArrayStructures(const ConcurrentJSLocker&) const { return !m_arrayProfileFlags.contains(ArrayProfileFlag::UsesNonOriginalArrayStructures); } + ArrayModes observedArrayModes() const { return m_observedArrayModes; } + bool mayInterceptIndexedAccesses() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayInterceptIndexedAccesses); } + + bool mayStoreToHole() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayStoreHole); } + bool outOfBounds() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::OutOfBounds); } + + bool usesOriginalArrayStructures() const { return !m_arrayProfileFlags.contains(ArrayProfileFlag::UsesNonOriginalArrayStructures); } - bool mayBeRegExpMatchesArray(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeRegExpMatchesArray); } + bool mayBeRegExpMatchesArray() const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeRegExpMatchesArray); } CString briefDescription(CodeBlock*); CString briefDescriptionWithoutUpdating(); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 0f0e2c18637b..09d4dd4403e8 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -401,6 +401,20 @@ CodeBlock::CodeBlock(VM& vm, Structure* structure, ScriptExecutable* ownerExecut checker().set(CrashChecker::Metadata, checker().hash(this, m_metadata.get())); } +static FunctionExecutable* instantiatedModuleFunctionExecutable(JSModuleEnvironment* moduleEnvironment, ScriptExecutable* topLevelExecutable, UnlinkedFunctionExecutable* unlinkedExecutable) +{ + SymbolTableEntry::Fast entry = moduleEnvironment->symbolTable()->get(unlinkedExecutable->name().impl()); + if (entry.isNull()) + return nullptr; + auto* function = dynamicDowncast(moduleEnvironment->variableAt(entry.scopeOffset()).get()); + if (!function) + return nullptr; + auto* executable = dynamicDowncast(function->executable()); + if (!executable || executable->unlinkedExecutable() != unlinkedExecutable || executable->topLevelExecutable() != topLevelExecutable) + return nullptr; + return executable; +} + // The main purpose of this function is to generate linked bytecode from unlinked bytecode. The process // of linking is taking an abstract representation of bytecode and tying it to a GlobalObject and scope // chain. For example, this process allows us to cache the depth of lexical environment reads that reach @@ -430,7 +444,9 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink // We already have the cloned symbol table for the module environment since we need to instantiate // the module environments before linking the code block. We replace the stored symbol table with the already cloned one. + JSModuleEnvironment* moduleEnvironment = nullptr; if (UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock = dynamicDowncast(unlinkedCodeBlock)) { + moduleEnvironment = uncheckedDowncast(scope); SymbolTable* clonedSymbolTable = uncheckedDowncast(ownerExecutable)->moduleEnvironmentSymbolTable(); if (m_unlinkedCode->wasCompiledWithTypeProfilerOpcodes()) { ConcurrentJSLocker locker(clonedSymbolTable->m_lock); @@ -445,7 +461,10 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i); if (shouldUpdateFunctionHasExecutedCache) vm.functionHasExecutedCache()->insertUnexecutedRange(ownerExecutable->sourceID(), unlinkedExecutable->unlinkedFunctionStart(), unlinkedExecutable->unlinkedFunctionEnd()); - m_functionDecls[i].set(vm, this, unlinkedExecutable->link(vm, topLevelExecutable, ownerExecutable->source(), std::nullopt, NoIntrinsic, ownerExecutable->isInsideOrdinaryFunction())); + FunctionExecutable* executable = moduleEnvironment ? instantiatedModuleFunctionExecutable(moduleEnvironment, topLevelExecutable, unlinkedExecutable) : nullptr; + if (!executable) + executable = unlinkedExecutable->link(vm, topLevelExecutable, ownerExecutable->source(), std::nullopt, NoIntrinsic, ownerExecutable->isInsideOrdinaryFunction()); + m_functionDecls[i].set(vm, this, executable); } m_functionExprs = FixedVector>(unlinkedCodeBlock->numberOfFunctionExprs()); @@ -1237,6 +1256,14 @@ void CodeBlock::visitChildren(Visitor& visitor) stronglyVisitStrongReferences(locker, visitor); stronglyVisitWeakReferences(locker, visitor); + + // Update profiles from concurrent markers to reduce the cost of update at the GC end phase as its execution is serialized. + if constexpr (std::is_same_v) { + if (visitor.isFirstVisit() && JITCode::isBaselineCode(jitType())) { + updateAllNonLazyValueProfilePredictions(); + updateAllLazyValueProfilePredictions(); + } + } Heap::CodeBlockSpaceAndSet::setFor(*subspace()).add(this); } @@ -2979,7 +3006,7 @@ void CodeBlock::didFailFTLCompilation() #endif -ArrayProfile* CodeBlock::getArrayProfile(const ConcurrentJSLocker&, BytecodeIndex bytecodeIndex) +ArrayProfile* CodeBlock::getArrayProfile(BytecodeIndex bytecodeIndex) { auto instruction = instructions().at(bytecodeIndex); @@ -3167,7 +3194,7 @@ void CodeBlock::updateAllArrayAllocationProfilePredictions() // Folds each profile's sampled value into a pointer-free SpeculatedType and clears the sample. // The samples are untraced JSValues and StructureIDs, so this only runs while they are still -// readable: after marking, before sweep. +// readable, which means any time from marking up to the sweep that would free them. void CodeBlock::updateAllPredictions() { updateAllNonLazyValueProfilePredictions(); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index 64ac1db6e6a5..747bc94452d8 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -451,7 +451,7 @@ class CodeBlock : public JSCell { bool NODELETE couldTakeSpecialArithFastCase(BytecodeIndex bytecodeOffset); - ArrayProfile* NODELETE getArrayProfile(const ConcurrentJSLocker&, BytecodeIndex); + ArrayProfile* NODELETE getArrayProfile(BytecodeIndex); // Exception handling support diff --git a/Source/JavaScriptCore/corpse/CMakeLists.txt b/Source/JavaScriptCore/corpse/CMakeLists.txt new file mode 100644 index 000000000000..f36085a527cd --- /dev/null +++ b/Source/JavaScriptCore/corpse/CMakeLists.txt @@ -0,0 +1,32 @@ +set(JavaScriptCoreTools_LIBRARY_TYPE STATIC) + +set(JavaScriptCoreTools_SOURCES + CorpseByteParser.cpp + CorpseClient.cpp + CorpseError.cpp + CorpseExportsTrie.cpp + CorpseProcess.cpp + CorpseRegion.cpp + CorpseSnapshot.cpp + CorpseSymbol.cpp + CorpseThread.cpp +) + +set(JavaScriptCoreTools_PRIVATE_INCLUDE_DIRECTORIES + $ +) + +set(JavaScriptCoreTools_FRAMEWORKS + JavaScriptCore + WTF + bmalloc +) + +WEBKIT_LIBRARY_DECLARE(JavaScriptCoreTools) + +WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() + +WEBKIT_LIBRARY(JavaScriptCoreTools) + +# The corpse sources use JavaScriptCore's generated headers. +add_dependencies(JavaScriptCoreTools JavaScriptCore) diff --git a/Source/JavaScriptCore/corpse/CorpseAddress.h b/Source/JavaScriptCore/corpse/CorpseAddress.h new file mode 100644 index 000000000000..ac83749e83d2 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseAddress.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include + +#if CPU(ARM64E) +#include +#endif + +namespace JSC { +namespace Corpse { + +// An address in the target corpse process. A corpse address can never be dereferenced +// by accident. +class Address { +public: + Address() = default; + explicit Address(mach_vm_address_t value) + : m_value(value) + { + } + explicit Address(const void* pointer) + : m_value(reinterpret_cast(pointer)) + { + } + + mach_vm_address_t toMachVMAddress() const { return m_value; } + explicit operator bool() const { return m_value; } + template explicit operator T() const = delete; + + Address stripped() const + { +#if CPU(ARM64E) + // We don't know if this is a code or data pointer. The 2 have different number of + // bits. But we know that code pointers have more PAC bits. So, we'll conservatively + // use XPACI to strip the max number of PAC bits. + auto stripped = ptrauth_strip(reinterpret_cast(m_value), ptrauth_key_process_dependent_code); + + // While XPACI may have already stripped the MTE tag in data pointers as well, + // we don't want to assume that code pointer PAC bits will always cover the MTE + // nibble or non-zero data pointer top-bytes due to TBI (Top Byte Ignore). So, + // let's explicitly clear the top byte to be sure. + constexpr uintptr_t topByte = 0xffull << 56; + uintptr_t strippedInt = std::bit_cast(stripped); + strippedInt &= ~topByte; + + return Address(std::bit_cast(strippedInt)); +#else + return *this; +#endif + } + + friend bool operator==(Address, Address) = default; + friend auto operator<=>(Address, Address) = default; + + friend bool operator==(Address address, std::nullptr_t) { return !address.m_value; } + + Address operator+(uint64_t offset) const { return Address(m_value + offset); } + Address operator-(uint64_t offset) const { return Address(m_value - offset); } + + uint64_t operator-(Address other) const { return m_value - other.m_value; } + +private: + mach_vm_address_t m_value { 0 }; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseByteParser.cpp b/Source/JavaScriptCore/corpse/CorpseByteParser.cpp new file mode 100644 index 000000000000..ea65768b3344 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseByteParser.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseByteParser.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include + +namespace JSC { +namespace Corpse { + +std::optional ByteParser::consumeByte() +{ + if (m_position >= m_data.size()) + return std::nullopt; + return m_data[m_position++]; +} + +std::optional ByteParser::consumeULEB128() +{ + size_t start = m_position; + uint64_t result = 0; + if (WTF::LEBDecoder::decodeUInt64(m_data, m_position, result)) + return result; + m_position = start; + return std::nullopt; +} + +std::optional ByteParser::consumeCString() +{ + size_t start = m_position; + while (m_position < m_data.size() && m_data[m_position]) + ++m_position; + if (m_position >= m_data.size()) { + m_position = start; + return std::nullopt; + } + std::string_view result(spanReinterpretCast(m_data.subspan(start, m_position - start))); + ++m_position; // Consume the null terminator. + return result; +} + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseByteParser.h b/Source/JavaScriptCore/corpse/CorpseByteParser.h new file mode 100644 index 000000000000..f5c404e03c1b --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseByteParser.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +// A forward byte parser over a local buffer. Every read reports whether it got +// what it asked for, and a read that fails consumes nothing. +class ByteParser { +public: + ByteParser(std::span data, size_t position = 0) + : m_data(data) + , m_position(position) + { + } + + size_t position() const { return m_position; } + + std::optional consumeByte(); + + // Decodes the ULEB128 at the cursor. Returns nullopt if the buffer ends + // before the encoding does, or if the value will not fit in 64 bits. + // Untrusted data can hold either, and silently truncating one would yield a + // plausible wrong value instead of a detected failure. + std::optional consumeULEB128(); + + // Returns the null-terminated string at the cursor. Returns nullopt if the + // buffer ends before the terminator does: without that the trailing bytes of + // a truncated buffer read back as a complete string. + std::optional consumeCString(); + +private: + std::span m_data; + size_t m_position; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseClient.cpp b/Source/JavaScriptCore/corpse/CorpseClient.cpp new file mode 100644 index 000000000000..800479f273de --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseClient.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseClient.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSC { +namespace Corpse { + +ASCIILiteral Client::s_clientName = "JSC::Corpse"_s; // Default if not set. + +void Client::setName(ASCIILiteral name) +{ + if (!name.isEmpty()) + s_clientName = name; +} + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/WebKit/NetworkProcess/EarlyHintsResourceLoader.h b/Source/JavaScriptCore/corpse/CorpseClient.h similarity index 54% rename from Source/WebKit/NetworkProcess/EarlyHintsResourceLoader.h rename to Source/JavaScriptCore/corpse/CorpseClient.h index 14aa69a3ca2e..b5ab8c1c380a 100644 --- a/Source/WebKit/NetworkProcess/EarlyHintsResourceLoader.h +++ b/Source/JavaScriptCore/corpse/CorpseClient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -25,35 +25,27 @@ #pragma once -#include "NetworkResourceLoader.h" -#include +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) -namespace WebCore { -class LinkHeader; -} +#include -namespace WebKit { +namespace JSC { +namespace Corpse { -class EarlyHintsResourceLoader - : public WebCore::ContentSecurityPolicyClient { - WTF_MAKE_TZONE_ALLOCATED(EarlyHintsResourceLoader); - WTF_MAKE_NONCOPYABLE(EarlyHintsResourceLoader); -public: - explicit EarlyHintsResourceLoader(NetworkResourceLoader&); - virtual ~EarlyHintsResourceLoader(); +// Currently, this is only to allow the client application to set the client name +// during initialization so that error messages identify with the client instead +// of the corpse library. - void handleEarlyHintsResponse(WebCore::ResourceResponse&&); +class Client { +public: + static void setName(ASCIILiteral); + static ASCIILiteral name() { return s_clientName; } private: - // ContentSecurityPolicyClient - void addConsoleMessage(MessageSource, MessageLevel, const String&, unsigned long requestIdentifier = 0) final; - void enqueueSecurityPolicyViolationEvent(WebCore::SecurityPolicyViolationEventInit&&) final; - - WebCore::ResourceRequest constructPreconnectRequest(const WebCore::ResourceRequest&, const URL&); - void startPreconnectTask(const URL& baseURL, const WebCore::LinkHeader&, const WebCore::ContentSecurityPolicy&); - - WeakPtr m_loader; - bool m_hasReceivedEarlyHints { false }; + static ASCIILiteral s_clientName; }; -} // namespace WebKit +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseError.cpp b/Source/JavaScriptCore/corpse/CorpseError.cpp new file mode 100644 index 000000000000..0f7ea774d502 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseError.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseError.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseClient.h" + +#include +#include + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace JSC { +namespace Corpse { + +void Error::report(const char* format, ...) +{ + fprintf(stderr, "%s: ", Client::name().characters()); + + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + fputc('\n', stderr); +} + +} // namespace Corpse +} // namespace JSC + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseError.h b/Source/JavaScriptCore/corpse/CorpseError.h new file mode 100644 index 000000000000..6a4ab690dd75 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseError.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include + +namespace JSC { +namespace Corpse { + +// Reports the library's diagnostics. Messages are prefixed with the name the +// client set via Corpse::Client, so they read as the client's own output. +class Error { +public: + static void report(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2); +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseExportsTrie.cpp b/Source/JavaScriptCore/corpse/CorpseExportsTrie.cpp new file mode 100644 index 000000000000..da6fa47ec71a --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseExportsTrie.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseExportsTrie.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include + +namespace JSC { +namespace Corpse { + +// The bits that Mach-O defines in an exports trie terminal's flags. +constexpr uint64_t knownExportFlagBits = EXPORT_SYMBOL_FLAGS_KIND_MASK + | EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION + | EXPORT_SYMBOL_FLAGS_REEXPORT + | EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER + | EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER; + +Expected ExportsTrie::lookUp(std::span trie, std::string_view name) +{ + size_t nodeOffset = 0; + std::string_view remaining = name; + + // The only way around this loop is by matching an edge, which consumes at least + // one character of the `remaining` name we're searching for. Because empty edges + // are rejected below, the walk is bounded by the length of the name no matter + // what the trie's child offsets say, and cannot be made to revisit a node forever. + while (nodeOffset < trie.size()) { + ByteParser node(trie, nodeOffset); + + // A terminal node in a dyld exports trie is: a length, then flags, then some + // ULEB128s whose meaning depends on the flags. See mach-o/loader.h around lines + // 1488–1499 for details. + auto terminalLength = node.consumeULEB128(); + if (!terminalLength) + return makeUnexpected(Failure::Malformed); + + // terminalLength is a full 64-bit value out of the trie, so it is compared + // against what is left of the trie rather than by forming position + terminalLength, + // which could wrap and pass a direct comparison. The subtraction is safe because + // consumeULEB128 stops at the end of the trie, so the position cannot have passed it. + if (*terminalLength > trie.size() - node.position()) + return makeUnexpected(Failure::Malformed); + size_t childrenPosition = node.position() + *terminalLength; + + if (remaining.empty() && *terminalLength) { + // The payload is read through a parser bounded to the terminal, so that a + // terminal declaring less than the flags and offset it needs cannot be made + // to take the bytes that follow it as its own. + ByteParser terminal(trie.subspan(node.position(), *terminalLength)); + auto flags = terminal.consumeULEB128(); + if (!flags) + return makeUnexpected(Failure::Malformed); + if (*flags & ~knownExportFlagBits) + return makeUnexpected(Failure::Malformed); + if (*flags & EXPORT_SYMBOL_FLAGS_REEXPORT) + return makeUnexpected(Failure::ReExport); + + Export::Kind kind; + switch (*flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) { + case EXPORT_SYMBOL_FLAGS_KIND_REGULAR: + kind = Export::Kind::Regular; + break; + case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: + kind = Export::Kind::Absolute; // the value is the address itself. + break; + default: + // Thread-local, or a kind postdating this code. A thread-local's value + // is the offset of its TLV descriptor, not of the variable, and the + // variable's address differs per thread, so there is no one answer to + // report. Saying nothing beats reporting the descriptor as if it were + // the variable. + return makeUnexpected(Failure::UnsupportedKind); + } + + auto value = terminal.consumeULEB128(); + if (!value) + return makeUnexpected(Failure::Malformed); + return Export { kind, *value }; + } + + ByteParser children(trie, childrenPosition); + auto childCount = children.consumeByte(); + if (!childCount) + return makeUnexpected(Failure::Malformed); + + std::optional nextNodeOffset; + for (uint8_t i = 0; i < *childCount; ++i) { + auto edge = children.consumeCString(); + if (!edge) + return makeUnexpected(Failure::Malformed); + // An edge carries the characters that tell a node's children apart, + // so an empty one is malformed. It would also match anything, and + // descending on it would consume none of the name. + if (edge->empty()) + return makeUnexpected(Failure::Malformed); + auto childOffset = children.consumeULEB128(); + if (!childOffset) + return makeUnexpected(Failure::Malformed); + if (remaining.starts_with(*edge)) { + remaining.remove_prefix(edge->size()); + nextNodeOffset = childOffset; + break; + } + } + // No edge matched what is left of the name, so nothing below this node + // can hold it. A node with no children ends the walk the same way. + if (!nextNodeOffset) + return makeUnexpected(Failure::Absent); + nodeOffset = *nextNodeOffset; + } + // A child offset led to or past the end of the trie. + return makeUnexpected(Failure::Malformed); +} + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseExportsTrie.h b/Source/JavaScriptCore/corpse/CorpseExportsTrie.h new file mode 100644 index 000000000000..f86d4bec637f --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseExportsTrie.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +// The dyld exports trie of one Mach-O image: a prefix tree over exported symbol +// names, whose terminals say how to compute each symbol's address. +// +// A trie read out of a corpse is untrusted input, so the walk is bounded and a +// malformed encoding is reported rather than guessed at. +class ExportsTrie { +public: + // A matched terminal, and how to turn it into an address. + struct Export { + enum class Kind : uint8_t { + Regular, // An offset from the image's base address. + Absolute, // Already an address, not relative to the image. + }; + Kind kind { Kind::Regular }; + uint64_t value { 0 }; + }; + + enum class Failure : uint8_t { + Absent, + Malformed, // An encoding did not decode, or an offset led outside the trie. + ReExport, // Matched, but the symbol is defined in another image. + UnsupportedKind, // Matched, but the kind has no one address, such as a thread-local. + }; + + static Expected lookUp(std::span trie, std::string_view name); +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseProcess.cpp b/Source/JavaScriptCore/corpse/CorpseProcess.cpp new file mode 100644 index 000000000000..d980d94701c0 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseProcess.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseProcess.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseError.h" + +#include +#include +#include +#include +#include +#include +#include + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace JSC { +namespace Corpse { + +// A task port name outlives the task it named: when the target exits, the right we +// hold becomes a dead name while the name itself is unchanged. MACH_PORT_VALID only +// looks at the name, so it keeps reporting the port as good. Asking the kernel which +// pid the port names is what tells a still-attached process apart from one that has +// since exited -- and, because the answer is compared against m_pid, from a later +// process that inherited the same pid. +bool Process::holdsLiveTask() const +{ + if (!MACH_PORT_VALID(m_taskPort)) + return false; + int pid = -1; + return pid_for_task(m_taskPort, &pid) == KERN_SUCCESS && pid == m_pid; +} + +bool Process::isTranslated() const +{ + struct kinfo_proc info; + size_t length = sizeof info; + int selector[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, m_pid }; + // A pid that no longer exists is not an error here: sysctl succeeds and reports + // that it wrote nothing, so the size has to be checked rather than the result. + if (sysctl(selector, 4, &info, &length, nullptr, 0) || length < sizeof info) + return false; + return info.kp_proc.p_flag & P_TRANSLATED; +} + +bool Process::attach() +{ + if (isAttached()) { + if (holdsLiveTask()) + return true; + // The target exited while we held its port. + detach(); + } + + mach_port_t taskPort = MACH_PORT_NULL; + kern_return_t kr = task_for_pid(mach_task_self(), m_pid, &taskPort); + if (kr == KERN_SUCCESS) { + m_taskPort = taskPort; + return true; + } + + if (kill(m_pid, 0) && errno == ESRCH) + Error::report("No process with PID %d", static_cast(m_pid)); + else { + Error::report("Could not attach to PID %u: %s (0x%x) -- may need to run as root " + "or add the appropriate debugger entitlement", + static_cast(m_pid), mach_error_string(kr), kr); + } + return false; +} + +void Process::detach() +{ + if (MACH_PORT_VALID(m_taskPort)) + mach_port_deallocate(mach_task_self(), m_taskPort); + m_taskPort = MACH_PORT_NULL; +} + +} // namespace Corpse +} // namespace JSC + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseProcess.h b/Source/JavaScriptCore/corpse/CorpseProcess.h new file mode 100644 index 000000000000..83df1bda88e1 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseProcess.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +// Represents a target corpse process identified by PID. It manages the Mach task +// port for that process: attach() acquires it, detach() releases it (but keeps the +// PID so the same Process can be reattached later). +class Process final : public RefCounted { +public: + static Ref create(pid_t pid) { return adoptRef(*new Process(pid)); } + + ~Process() { detach(); } + + bool attach(); + void detach(); + + pid_t pid() const { return m_pid; } + mach_port_t taskPort() const { return m_taskPort; } + + bool isAttached() const { return MACH_PORT_VALID(m_taskPort); } + + // The target process may have terminated while we still hold the port. + bool holdsLiveTask() const; + + // True if the target runs under Rosetta translation. Such a process executes as + // arm64 whatever its own architecture is, so its thread state describes the + // translator rather than the program, and cannot be read as the program's. + bool isTranslated() const; + +private: + explicit Process(pid_t pid) + : m_pid(pid) + { + RELEASE_ASSERT(pid > 0); + } + + pid_t m_pid; + mach_port_t m_taskPort { MACH_PORT_NULL }; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseRegion.cpp b/Source/JavaScriptCore/corpse/CorpseRegion.cpp new file mode 100644 index 000000000000..7d912d228ca3 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseRegion.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseRegion.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include + +namespace JSC { +namespace Corpse { + +uint64_t Region::pageCount() const +{ + return vm_kernel_page_size ? m_size / vm_kernel_page_size : 0; +} + +std::optional Region::findContaining(mach_port_t task, Address address) +{ + // mach_vm_region_recurse reports the region at or above the address it is given, + // so the result only describes `address` if it turns out to contain it. + mach_vm_address_t regionAddress = 0; + mach_vm_size_t regionSize = 0; + vm_region_submap_info_data_64_t info; + for (natural_t depth = 0; ; ++depth) { + regionAddress = address.toMachVMAddress(); + regionSize = 0; + natural_t depthLimit = depth; // We tell the kernel how deep we want to go. Kernel tells us how deep it can go. + mach_msg_type_number_t infoCount = VM_REGION_SUBMAP_INFO_COUNT_64; + kern_return_t kr = mach_vm_region_recurse(task, ®ionAddress, ®ionSize, + &depthLimit, reinterpret_cast(&info), &infoCount); + if (kr != KERN_SUCCESS) + return std::nullopt; + if (!info.is_submap) + break; + } + + Region region; + region.m_base = Address(regionAddress); + region.m_size = static_cast(regionSize); + if (!region.contains(address)) + return std::nullopt; + + region.m_residentPageCount = info.pages_resident; + region.m_dirtyPageCount = info.pages_dirtied; + return region; +} + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseRegion.h b/Source/JavaScriptCore/corpse/CorpseRegion.h new file mode 100644 index 000000000000..d2bfcaa0adb6 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseRegion.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +// One mapped region of a task's address space, as the kernel describes it. +class Region { +public: + // The region containing `address`, or nullopt if not found in any region. + static std::optional findContaining(mach_port_t task, Address); + + Address base() const { return m_base; } + size_t size() const { return m_size; } + Address end() const { return m_base + m_size; } + bool contains(Address address) const { return address >= m_base && address < end(); } + + uint64_t pageCount() const; + uint64_t residentPageCount() const { return m_residentPageCount; } + uint64_t dirtyPageCount() const { return m_dirtyPageCount; } + +private: + Address m_base; + size_t m_size { 0 }; + uint64_t m_residentPageCount { 0 }; + uint64_t m_dirtyPageCount { 0 }; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseSnapshot.cpp b/Source/JavaScriptCore/corpse/CorpseSnapshot.cpp new file mode 100644 index 000000000000..14107ca4c9c5 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseSnapshot.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseSnapshot.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseError.h" + +#include +#include +#include + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace JSC { +namespace Corpse { + +WTF_MAKE_TZONE_ALLOCATED_IMPL(Snapshot); + +unsigned Snapshot::s_nextId = 1; + +Snapshot::Snapshot(RefPtr process) + : m_process(WTF::move(process)) + , m_id(s_nextId++) +{ + if (!m_process || !m_process->isAttached()) + return; + + // Snapshot the target into a corpse; only a read port is required from here + // on, and the corpse is independent of the live target. + kern_return_t kr = task_generate_corpse(m_process->taskPort(), &m_corpsePort); + if (kr != KERN_SUCCESS) { + m_corpsePort = MACH_PORT_NULL; + if (!m_process->holdsLiveTask()) { + Error::report("Could not snapshot PID %d: the process has terminated", + static_cast(m_process->pid())); + } else { + Error::report("Could not snapshot PID %d: %s (0x%x)", + static_cast(m_process->pid()), mach_error_string(kr), kr); + } + } +} + +Snapshot::~Snapshot() +{ + if (isValid()) + mach_port_deallocate(mach_task_self(), m_corpsePort); +} + +const Vector& Snapshot::threads() +{ + if (!m_threads) + m_threads = Thread::collect(*this); + return *m_threads; +} + +Address Snapshot::symbol(const char* name) +{ + if (!name || !*name) + return { }; + + auto entry = m_symbols.ensure(StringView::fromLatin1(name), [&] { + return WTF::makeUnique(*this, name); + }); + + return entry.iterator->value->address(); +} + +} // namespace Corpse +} // namespace JSC + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseSnapshot.h b/Source/JavaScriptCore/corpse/CorpseSnapshot.h new file mode 100644 index 000000000000..3013bf605022 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseSnapshot.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +// Owns a corpse (a read-only Mach snapshot of a process) +// Check isValid() to see whether acquisition succeeded. +// +// Snapshots are linked into a DoublyLinkedList by their owner. The list is +// intrusive and does not own its nodes: whoever appends a Snapshot must remove +// it from the list before destroying it. +class Snapshot : public DoublyLinkedListNode { + WTF_MAKE_TZONE_ALLOCATED(Snapshot); +public: + explicit Snapshot(RefPtr); + ~Snapshot(); + + Snapshot(const Snapshot&) = delete; + Snapshot& operator=(const Snapshot&) = delete; + Snapshot(Snapshot&& other) = delete; + + bool isValid() const { return MACH_PORT_VALID(m_corpsePort); } + + // A monotonically increasing identifier assigned at construction. IDs are + // never reused, so they stay stable as snapshots are added and removed. + unsigned id() const { return m_id; } + + Process* process() const { return m_process.get(); } + mach_port_t corpsePort() const { return m_corpsePort; } + + // The threads captured in this corpse, read and cached on the first call. + const Vector& threads(); + + // The address of `name` in this corpse, null if it is not there. + Address symbol(const char* name); + +private: + static unsigned s_nextId; + + RefPtr m_process; + mach_port_t m_corpsePort { MACH_PORT_NULL }; + unsigned m_id; + + std::optional> m_threads; + HashMap> m_symbols; + + Snapshot* m_prev { nullptr }; // Required by DoublyLinkedListNode. + Snapshot* m_next { nullptr }; // Required by DoublyLinkedListNode. + + friend class WTF::DoublyLinkedListNode; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseSymbol.cpp b/Source/JavaScriptCore/corpse/CorpseSymbol.cpp new file mode 100644 index 000000000000..a968dfa30a1b --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseSymbol.cpp @@ -0,0 +1,481 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseSymbol.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseError.h" +#include "CorpseExportsTrie.h" +#include "CorpseSnapshot.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS +#define CORPSE_DIAGNOSTIC_DO(statement) statement +#else +#define CORPSE_DIAGNOSTIC_DO(statement) ((void)0) +#endif + +namespace JSC { +namespace Corpse { + +WTF_MAKE_TZONE_ALLOCATED_IMPL(Symbol); + +// It is assumed that this corpse analysis library is built with the same SDK targeting +// the same OS that the corpse binary is built for. While the corpse gives us the data +// to inspect, it does not provide the format. Hence, we need to rely on the invariant +// that this analysis library is built with the same understanding of the same data +// format used in the corpse. This is how we can walk and interpret the corpse's +// dyld exports trie and get addresses of symbols. + +namespace { + +// Sizes and counts read out of a corpse are used to bound loops and to size +// allocations, so they are checked against these limits first. Each one is a +// sanity check on a single value: it says the struct we read was not what we +// thought it was, in which case the addresses in it are not worth chasing. They +// are not a bound on the work a lookup can do, because the per-image limits +// multiply by the image count. maxTotalBytesRead below is that bound. +// +// The values sit above what was empirically measured: across every Mach-O image +// installed on a sample system the largest load commands were 7.4 KB and the +// largest exports trie 2.1 MB, and a process that dlopens every framework on the +// system reaches about 2,800 images. +constexpr size_t maxLoadCommandsSize = 128 * KB; // About 17× the measured maximum. +constexpr size_t maxExportsTrieSize = 16 * MB; // About 8× the measured maximum. +constexpr uint32_t maxImageCount = 16 * 1024; // About 6× the measured maximum. + +// A lookup that finds nothing will read every image's load commands and exports +// trie, which measured 101 MB for the ~2,800 image process above and 0.4 MB for +// a small one. This caps the total for one lookup, so a corpse claiming many +// large images cannot turn a single symbol lookup into unbounded copying. +constexpr size_t maxTotalBytesRead = 256 * MB; // About 2.5× the measured maximum. + +// Copies data from a corpse task's virtual address space. +// FIXME: This is a temporary "get things to work solution", and will be replaced with +// a more efficient memory access from a page manager later that eliminates copying. +class TaskMemory { +public: + explicit TaskMemory(mach_port_t task) + : m_task(task) + { + } + + template + std::optional read(Address address) const + { + static_assert(std::is_trivially_copyable_v); + T out; + if (!readRaw(address, &out, sizeof out)) + return std::nullopt; + return out; + } + + std::optional> readBytes(Address address, size_t length) const + { + Vector buffer; + // Callers derive `length` from the corpse, so failing to allocate is a + // potential outcome here due to potential corruption. + if (!buffer.tryGrow(length)) + return std::nullopt; + if (!readRaw(address, buffer.mutableSpan().data(), length)) + return std::nullopt; + return buffer; + } + +private: + bool readRaw(Address address, void* destination, size_t length) const + { + mach_vm_size_t got = 0; + kern_return_t kr = mach_vm_read_overwrite(m_task, address.toMachVMAddress(), length, + reinterpret_cast(destination), &got); + return kr == KERN_SUCCESS && got == length; + } + + mach_port_t m_task; +}; + +template +std::optional readCommand(std::span commands, size_t offset) +{ + static_assert(std::is_trivially_copyable_v); + // Compared against what is left of the buffer rather than by forming + // offset + sizeof(T), which could wrap and pass a direct comparison. The + // first clause is what makes the subtraction safe. + if (offset > commands.size() || commands.size() - offset < sizeof(T)) + return std::nullopt; + + T value; + memcpySpan(asMutableByteSpan(value), commands.subspan(offset, sizeof(T))); + return value; +} + +bool segmentNameIs(const char (&name)[16], std::string_view expected) +{ + // A segment name fills the whole array when it is exactly 16 characters, in + // which case it has no terminator. + std::span span { name }; + return std::string_view(span.first(strlenSpan(span))) == expected; +} + +} // anonymous namespace + +bool Symbol::hasReadBudget(size_t length) +{ + if (length > m_readBudget) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.readBudgetExhausted); + return false; + } + m_readBudget -= length; + return true; +} + +// Resolves `name` in the one image loaded at `imageAddress`, via its exports +// trie. Returns a null address if this image does not export it. +Address Symbol::resolveInImage(mach_port_t task, Address imageAddress, std::string_view name) +{ + TaskMemory memory(task); + + auto header = memory.read(imageAddress); + if (!header || header->magic != MH_MAGIC_64) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.unreadableHeader); + return { }; + } + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.examined); + if (header->flags & MH_DYLIB_IN_CACHE) + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.inSharedCache); + + if (header->sizeofcmds > maxLoadCommandsSize) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.implausibleCommandsSize); + return { }; + } + if (!hasReadBudget(header->sizeofcmds)) + return { }; + auto commandsBuffer = memory.readBytes(imageAddress + sizeof(mach_header_64), header->sizeofcmds); + if (!commandsBuffer) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.unreadableCommands); + return { }; + } + std::span commands = commandsBuffer->span(); + + std::optional textVMAddress; + std::optional linkeditVMAddress; + std::optional linkeditFileOffset; + std::optional linkeditFileSize; + uint32_t exportOffset = 0; + uint32_t exportSize = 0; + + size_t offset = 0; + for (uint32_t i = 0; i < header->ncmds; ++i) { + auto command = readCommand(commands, offset); + // cmdsize is compared against what is left of the blob rather than by + // forming offset + cmdsize, which could wrap and pass a direct + // comparison. The subtraction is safe only because a successful + // readCommand has already established that offset is within the blob, + // so the clauses have to stay in this order. + if (!command || command->cmdsize < sizeof(load_command) || command->cmdsize > commands.size() - offset) + break; + + // Each case below re-reads `offset` as the larger struct the command + // claims to be. cmdsize has to cover that struct too: a command that + // declares itself smaller is malformed, and reading it anyway would take + // the fields that follow it as its own. + switch (command->cmd) { + case LC_SEGMENT_64: { + if (command->cmdsize < sizeof(segment_command_64)) + break; + auto segment = readCommand(commands, offset); + if (!segment) + break; + if (segmentNameIs(segment->segname, SEG_TEXT)) + textVMAddress = segment->vmaddr; + else if (segmentNameIs(segment->segname, SEG_LINKEDIT)) { + linkeditVMAddress = segment->vmaddr; + linkeditFileOffset = segment->fileoff; + linkeditFileSize = segment->filesize; + } + break; + } + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: { + if (command->cmdsize < sizeof(dyld_info_command)) + break; + auto info = readCommand(commands, offset); + if (!info) + break; + exportOffset = info->export_off; + exportSize = info->export_size; + break; + } + case LC_DYLD_EXPORTS_TRIE: { + if (command->cmdsize < sizeof(linkedit_data_command)) + break; + auto data = readCommand(commands, offset); + if (!data) + break; + exportOffset = data->dataoff; + exportSize = data->datasize; + break; + } + default: + break; + } + offset += command->cmdsize; + } + + if (!textVMAddress || !linkeditVMAddress || !linkeditFileOffset || !linkeditFileSize || !exportSize) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.withoutTrie); + return { }; + } + if (exportSize > maxExportsTrieSize) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.implausibleTrieSize); + return { }; + } + + // The trie is file-backed data living inside __LINKEDIT. So, exportOffset cannot + // be less than the start of __LINKEDIT, cannot exceed the end of __LINKEDIT, and + // the whole trie must fit inside it. + if (exportOffset < *linkeditFileOffset) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.trieOutsideLinkedit); + return { }; + } + uint64_t trieSegmentOffset = exportOffset - *linkeditFileOffset; + if (trieSegmentOffset > *linkeditFileSize || exportSize > *linkeditFileSize - trieSegmentOffset) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.trieOutsideLinkedit); + return { }; + } + + // __TEXT's link-time address against where the image actually landed. The + // load commands give link-time addresses, so everything read out of them + // needs this added to reach the corpse. + uint64_t slide = imageAddress - Address(*textVMAddress); + Address trieAddress = Address(*linkeditVMAddress) + slide + trieSegmentOffset; + + if (!hasReadBudget(exportSize)) + return { }; + auto trieBuffer = memory.readBytes(trieAddress, exportSize); + if (!trieBuffer) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.unreadableTrie); + return { }; + } + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.searched); + + auto found = ExportsTrie::lookUp(trieBuffer->span(), name); + if (!found) { +#if CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS + if (found.error() == ExportsTrie::Failure::ReExport) + ++m_diagnostics.reExports; + else if (found.error() == ExportsTrie::Failure::UnsupportedKind) + ++m_diagnostics.unsupportedKind; +#endif + return { }; + } + if (found->kind == ExportsTrie::Export::Kind::Absolute) + return Address(found->value); + return imageAddress + found->value; +} + +Address Symbol::lookUpName(const Snapshot& snapshot) +{ + if (!snapshot.isValid() || m_name.empty()) + return { }; + + m_readBudget = maxTotalBytesRead; + + auto doLookUp = [&] () -> Address { + std::string name = "_" + m_name; // Use Mach-O symbol name for look up. + + mach_port_t task = snapshot.corpsePort(); + TaskMemory memory(task); + + // dyld publishes the list of loaded images; search each one in turn. + task_dyld_info_data_t dyldInfo; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(task, TASK_DYLD_INFO, reinterpret_cast(&dyldInfo), &count) != KERN_SUCCESS) + return { }; + CORPSE_DIAGNOSTIC_DO(m_diagnostics.readDyldInfo = true); + + Address allImageInfosAddress { dyldInfo.all_image_info_addr }; + CORPSE_DIAGNOSTIC_DO(m_diagnostics.allImageInfosAddress = allImageInfosAddress); + if (!allImageInfosAddress) + return { }; + + auto allImages = memory.read(allImageInfosAddress); + if (!allImages) + return { }; + CORPSE_DIAGNOSTIC_DO(m_diagnostics.readAllImageInfos = true); + CORPSE_DIAGNOSTIC_DO(m_diagnostics.version = allImages->version); + + Address rawArrayAddress { allImages->infoArray }; + Address arrayAddress = rawArrayAddress.stripped(); + uint32_t imageCount = allImages->infoArrayCount; + CORPSE_DIAGNOSTIC_DO(m_diagnostics.rawImageArrayAddress = rawArrayAddress); + CORPSE_DIAGNOSTIC_DO(m_diagnostics.imageArrayAddress = arrayAddress); + CORPSE_DIAGNOSTIC_DO(m_diagnostics.images = imageCount); + if (!arrayAddress || !imageCount) + return { }; + // Each image below costs a Mach round-trip and two buffer reads, so an + // implausible count is a lot of work to be talked into doing. + if (imageCount > maxImageCount) { + CORPSE_DIAGNOSTIC_DO(m_diagnostics.implausibleImageCount = true); + return { }; + } + + for (uint32_t i = 0; i < imageCount; ++i) { + auto info = memory.read(arrayAddress + static_cast(i) * sizeof(dyld_image_info)); + if (!info) { + CORPSE_DIAGNOSTIC_DO(++m_diagnostics.unreadableInfo); + continue; + } + auto imageAddress = Address(info->imageLoadAddress).stripped(); + auto symbolAddress = resolveInImage(task, imageAddress, name); + if (symbolAddress) + return symbolAddress; + } + + return { }; + }; + + Address address = doLookUp(); +#if CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS + if (!address) + reportFailure(snapshot); +#endif + return address; +} + +#if CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS + +// Says how a failed search went, so a caller can tell "the symbol is not +// exported" from "the corpse could not be read". +void Symbol::reportFailure(const Snapshot& snapshot) const +{ + const Diagnostics& d = m_diagnostics; + + Error::report("No symbol '_%s' in pid %d", m_name.c_str(), + static_cast(snapshot.process()->pid())); + + if (!d.readDyldInfo) { + Error::report(" could not read dyld information (task_info TASK_DYLD_INFO failed)"); + return; + } + if (!d.allImageInfosAddress) { + Error::report(" dyld reports no image list (all_image_info_addr is 0)"); + return; + } + if (!d.readAllImageInfos) { + Error::report(" could not read dyld_all_image_infos at 0x%llx", + d.allImageInfosAddress.toMachVMAddress()); + return; + } + + // A sane version says the struct read probably landed on real data, which is what + // makes the image count and array address below worth printing. + Error::report(" dyld_all_image_infos v%u at 0x%llx lists %u images at 0x%llx", + d.version, d.allImageInfosAddress.toMachVMAddress(), + d.images, d.imageArrayAddress.toMachVMAddress()); + if (d.rawImageArrayAddress != d.imageArrayAddress) { + Error::report(" that address was ptrauth-signed as 0x%llx; the signature was stripped", + d.rawImageArrayAddress.toMachVMAddress()); + } + if (!d.imageArrayAddress || !d.images) { + Error::report(" that list is empty, so there was nothing to search"); + return; + } + if (d.implausibleImageCount) { + Error::report(" that count is too large to be a real image list, so the struct read" + " was not dyld_all_image_infos and was not searched"); + return; + } + + Error::report(" read %u of %u image headers (%u in the shared cache), walked %u exports tries", + d.examined, d.images, d.inSharedCache, d.searched); + if (d.unreadableInfo) + Error::report(" %u image list entries were unreadable", d.unreadableInfo); + if (d.unreadableHeader) + Error::report(" %u image headers were unreadable or not 64-bit Mach-O", d.unreadableHeader); + if (d.implausibleCommandsSize) + Error::report(" %u images had implausible load command sizes", d.implausibleCommandsSize); + if (d.unreadableCommands) + Error::report(" %u images had unreadable load commands", d.unreadableCommands); + if (d.withoutTrie) + Error::report(" %u images had no exports trie", d.withoutTrie); + if (d.implausibleTrieSize) + Error::report(" %u images had implausible exports trie sizes", d.implausibleTrieSize); + if (d.trieOutsideLinkedit) + Error::report(" %u images placed their exports trie outside __LINKEDIT", d.trieOutsideLinkedit); + if (d.unreadableTrie) + Error::report(" %u exports tries were not readable", d.unreadableTrie); + if (d.readBudgetExhausted) { + Error::report(" gave up after reading %u MB from the corpse; %u images were skipped", + static_cast(maxTotalBytesRead / MB), d.readBudgetExhausted); + } + if (d.reExports) + Error::report(" %u images re-export the name from elsewhere, which is not followed", d.reExports); + if (d.unsupportedKind) + Error::report(" %u images export the name in a form that has no single address, such as a thread-local", d.unsupportedKind); + + if (d.searched) { + Error::report( + " only exported symbols appear in an exports trie: a symbol hidden" + " by the linker is invisible here even though lldb can still find" + " it in the symbol table"); + } else { + Error::report( + " no trie was searched, so this is a memory-access problem rather" + " than the symbol being absent"); + } +} + +#endif // CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS + +Symbol::Symbol(const Snapshot& snapshot, const char* name) + : m_name(name ? name : "") +{ + if (!m_name.empty()) + m_address = lookUpName(snapshot); +} + +} // namespace Corpse +} // namespace JSC + +#undef CORPSE_DIAGNOSTIC_DO + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseSymbol.h b/Source/JavaScriptCore/corpse/CorpseSymbol.h new file mode 100644 index 000000000000..e32f53d98e09 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseSymbol.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include + +// Enable for more detailed error messages on what may have caused a symbol lookup failure. +#define CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS 0 + +namespace JSC { +namespace Corpse { + +class Snapshot; + +// A symbol looked up in a corpse by name. The lookup happens on construction. +// +// Only regular and absolute exports are read out of an image's trie. A re-export is +// skipped rather than followed, so a name that one image re-exports resolves in the +// image that defines it, as long as that image is loaded in the corpse. A +// thread-local is not found at all. +// +// A re-export may also rename, and then no image exports the name at all: memcpy +// exists only as libsystem_c's re-export of __platform_memmove from +// libsystem_platform, so a lookup of memcpy finds nothing while a lookup of +// __platform_memmove succeeds. +class Symbol { + WTF_MAKE_TZONE_ALLOCATED(Symbol); +public: + Symbol(const Snapshot&, const char* name); + + const std::string& name() const { return m_name; } + + Address address() const { return m_address; } // Null means not found. + bool isValid() const { return static_cast(m_address); } + +private: + Address lookUpName(const Snapshot&); + Address resolveInImage(mach_port_t, Address loadAddress, std::string_view name); + bool hasReadBudget(size_t length); + +#if CORPSE_SYMBOL_LOOKUP_DIAGNOSTICS + // How far a search got, so a failure can name the stage that fell short. + struct Diagnostics { + bool readDyldInfo { false }; + Address allImageInfosAddress; + bool readAllImageInfos { false }; + uint32_t version { 0 }; // dyld_all_image_infos::version. + Address rawImageArrayAddress; // As stored, possibly signed. + Address imageArrayAddress; // ...with any signature stripped. + unsigned images { 0 }; // Images dyld reported. + bool implausibleImageCount { false }; // ...but too many to be believed. + unsigned examined { 0 }; // ...whose Mach header we read. + unsigned inSharedCache { 0 }; // ...of those, in the shared cache. + unsigned unreadableInfo { 0 }; // dyld_image_info unreadable. + unsigned unreadableHeader { 0 }; // Header missing or not 64-bit. + unsigned implausibleCommandsSize { 0 }; // sizeofcmds too large to believe. + unsigned unreadableCommands { 0 }; // Load commands unreadable. + unsigned withoutTrie { 0 }; // No trie, or no __TEXT/__LINKEDIT. + unsigned implausibleTrieSize { 0 }; // Trie size too large to believe. + unsigned trieOutsideLinkedit { 0 }; // Trie not within __LINKEDIT. + unsigned unreadableTrie { 0 }; // Trie located but not readable. + unsigned readBudgetExhausted { 0 }; // Gave up: the lookup hit its read budget. + unsigned searched { 0 }; // Tries actually walked. + unsigned reExports { 0 }; // Matched, but re-exported. + unsigned unsupportedKind { 0 }; // Matched, but not an export kind with one address. + }; + + void reportFailure(const Snapshot&) const; + + Diagnostics m_diagnostics; +#endif + + std::string m_name; + Address m_address; + + // What this lookup may still copy out of the corpse. Set when the search starts. + size_t m_readBudget { 0 }; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseThread.cpp b/Source/JavaScriptCore/corpse/CorpseThread.cpp new file mode 100644 index 000000000000..f70ee5151c61 --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseThread.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseThread.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseError.h" +#include "CorpseProcess.h" +#include "CorpseRegion.h" +#include "CorpseSnapshot.h" + +#include +#include +#include +#include +#include +#include +#include + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace JSC { +namespace Corpse { + +static std::optional
readStackPointer(thread_act_t thread) +{ +#if CPU(ARM64) + arm_thread_state64_t state = { }; + mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT; + if (thread_get_state(thread, ARM_THREAD_STATE64, reinterpret_cast(&state), &count) != KERN_SUCCESS) + return std::nullopt; // May fail e.g. for Rosetta. + // The target's pc/lr/sp/fp arrive signed for its own ptrauth context. On an + // arm64e build the accessors would try to authenticate them against ours and + // trap (EXC_BAD_ACCESS / EXC_ARM_PAC_FAIL), so strip the signatures first. + // Stripping also marks the state as unsigned, so the accessor reads it raw. + arm_thread_state64_ptrauth_strip(state); + return Address(arm_thread_state64_get_sp(state)); +#elif CPU(X86_64) + x86_thread_state64_t state = { }; + mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; + if (thread_get_state(thread, x86_THREAD_STATE64, reinterpret_cast(&state), &count) != KERN_SUCCESS) + return std::nullopt; + return Address(state.__rsp); +#else + UNUSED_PARAM(thread); + return std::nullopt; +#endif +} + +const char* Thread::runStateDescription() const +{ + switch (m_runState) { + case TH_STATE_RUNNING: + return "running"; + case TH_STATE_STOPPED: + return "stopped"; + case TH_STATE_WAITING: + return "waiting"; + case TH_STATE_UNINTERRUPTIBLE: + return "uninterruptible"; + case TH_STATE_HALTED: + return "halted"; + default: + return "unknown"; + } +} + +Vector Thread::collect(const Snapshot& snapshot) +{ + Vector result; + + if (!snapshot.isValid()) { + Error::report("Cannot read threads from an invalid snapshot"); + return result; + } + mach_port_t task = snapshot.corpsePort(); + + thread_act_array_t threads = nullptr; + mach_msg_type_number_t threadCount = 0; + kern_return_t kr = task_threads(task, &threads, &threadCount); + if (kr != KERN_SUCCESS) { + pid_t pid = snapshot.process()->pid(); + Error::report("Could not read the thread list for pid %d: %s (0x%x)", + static_cast(pid), mach_error_string(kr), kr); + return result; + } + + result.reserveCapacity(threadCount); + + // A translated target executes as arm64 whatever its own architecture is, so its + // threads' stack pointers belong to Rosetta's runtime rather than to the program. + // Those addresses do land in real mappings, so reporting the region around one + // would name a plausible but wrong stack; report no stack instead. + Process* process = snapshot.process(); + bool isTranslated = process->isTranslated(); + if (isTranslated) { + Error::report("Thread stacks for pid %d are not available: the process runs" + " under Rosetta translation, whose thread state does not describe the program", + static_cast(process->pid())); + } + + unsigned unreadableStates = 0; + for (mach_msg_type_number_t i = 0; i < threadCount; ++i) { + Thread thread; + + thread_identifier_info_data_t identifierInfo; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + if (thread_info(threads[i], THREAD_IDENTIFIER_INFO, reinterpret_cast(&identifierInfo), &count) == KERN_SUCCESS) + thread.m_id = identifierInfo.thread_id; + + thread_basic_info_data_t basicInfo; + count = THREAD_BASIC_INFO_COUNT; + if (thread_info(threads[i], THREAD_BASIC_INFO, reinterpret_cast(&basicInfo), &count) == KERN_SUCCESS) { + thread.m_runState = basicInfo.run_state; + thread.m_suspendCount = basicInfo.suspend_count; + thread.m_userTimeUsec = static_cast(basicInfo.user_time.seconds) * 1000000 + + basicInfo.user_time.microseconds; + thread.m_systemTimeUsec = static_cast(basicInfo.system_time.seconds) * 1000000 + + basicInfo.system_time.microseconds; + } + + // Extended info is the only flavor that reports the pthread name. + thread_extended_info_data_t extendedInfo; + count = THREAD_EXTENDED_INFO_COUNT; + if (thread_info(threads[i], THREAD_EXTENDED_INFO, reinterpret_cast(&extendedInfo), &count) == KERN_SUCCESS) { + extendedInfo.pth_name[sizeof(extendedInfo.pth_name) - 1] = '\0'; + thread.m_name = extendedInfo.pth_name; + } + + // The stack is the region the stack pointer points into. + if (!isTranslated) { + if (auto stackPointer = readStackPointer(threads[i])) { + thread.m_stackPointer = *stackPointer; + if (auto region = Region::findContaining(task, thread.m_stackPointer)) + thread.m_stackRegion = *region; + } else + ++unreadableStates; + } + + result.append(thread); + } + + // Failing to read the thread state leaves a thread with no stack, which on its + // own looks the same as a thread that has none. Say which it was. + if (unreadableStates) { + Error::report("Could not read the thread state of %u of %u threads in pid %d:" + " this build cannot read the target's architecture", + unreadableStates, static_cast(threadCount), + static_cast(process->pid())); + } + + // task_threads hands us a right to each thread plus the array itself. + for (mach_msg_type_number_t i = 0; i < threadCount; ++i) + mach_port_deallocate(mach_task_self(), threads[i]); + mach_vm_size_t threadsSize = threadCount * sizeof(thread_act_t); + mach_vm_deallocate(mach_task_self(), reinterpret_cast(threads), threadsSize); + + return result; +} +} // namespace Corpse +} // namespace JSC + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/CorpseThread.h b/Source/JavaScriptCore/corpse/CorpseThread.h new file mode 100644 index 000000000000..64b2ae2d433f --- /dev/null +++ b/Source/JavaScriptCore/corpse/CorpseThread.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { + +class Snapshot; + +// A snapshot of thread values read out of a corpse. +class Thread { +public: + // The kernel's system-wide unique 64-bit thread id, as reported by lldb and + // spindump. This is an identifier, not an address. + uint64_t id() const { return m_id; } + + // The pthread name, empty if the thread was never named. + const std::string& name() const { return m_name; } + + int runState() const { return m_runState; } + int suspendCount() const { return m_suspendCount; } + uint64_t userTimeUsec() const { return m_userTimeUsec; } + uint64_t systemTimeUsec() const { return m_systemTimeUsec; } + + Address stackPointer() const { return m_stackPointer; } + + const Region& stackRegion() const { return m_stackRegion; } + bool hasStack() const { return m_stackRegion.size(); } + + const char* runStateDescription() const; + +private: + static Vector collect(const Snapshot&); + + uint64_t m_id { 0 }; + std::string m_name; + int m_runState { 0 }; + int m_suspendCount { 0 }; + uint64_t m_userTimeUsec { 0 }; + uint64_t m_systemTimeUsec { 0 }; + Address m_stackPointer; + Region m_stackRegion; + + friend class Snapshot; +}; + +} // namespace Corpse +} // namespace JSC + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.cpp new file mode 100644 index 000000000000..4f3e685bba92 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseAddressTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include + +#if CPU(ARM64E) +#include +#endif + +namespace JSCToolsTest { + +using JSC::Corpse::Address; + +void testAddress() +{ + if (!beginSuite("Address")) + return; + + { + Address none; + TEST_ASSERT(!none, "a default Address is null"); + TEST_ASSERT(none == nullptr, "a default Address compares equal to nullptr"); + TEST_ASSERT_HEX_EQ(none.toMachVMAddress(), 0, "a default Address holds zero"); + } + { + Address address(static_cast(0x1000)); + TEST_ASSERT(static_cast(address), "a non-zero Address is not null"); + TEST_ASSERT(!(address == nullptr), "a non-zero Address does not compare equal to nullptr"); + TEST_ASSERT_HEX_EQ(address.toMachVMAddress(), 0x1000, "an Address holds what it was given"); + } + { + int local = 0; + Address address(&local); + TEST_ASSERT_HEX_EQ(address.toMachVMAddress(), reinterpret_cast(&local), + "an Address built from a pointer holds that pointer"); + } + { + // The whole point of the type: a corpse address must not be usable as a + // local one by accident, so there is no conversion out of it. + TEST_ASSERT(!(std::is_convertible_v), + "an Address does not convert to an integer"); + TEST_ASSERT(!(std::is_convertible_v), + "an Address does not convert to a pointer"); + } + { + Address low(static_cast(0x1000)); + Address high(static_cast(0x2000)); + TEST_ASSERT(low < high, "Addresses order by value"); + TEST_ASSERT(high > low, "Addresses order by value the other way"); + TEST_ASSERT(low <= low && low >= low, "an Address is not less or greater than itself"); + TEST_ASSERT(low == Address(static_cast(0x1000)), "equal values compare equal"); + TEST_ASSERT(low != high, "different values do not compare equal"); + } + { + Address base(static_cast(0x1000)); + TEST_ASSERT_HEX_EQ((base + 0x20).toMachVMAddress(), 0x1020, "adding an offset moves forward"); + TEST_ASSERT_HEX_EQ((base - 0x20).toMachVMAddress(), 0x0fe0, "subtracting an offset moves back"); + TEST_ASSERT_HEX_EQ(Address(static_cast(0x1030)) - base, 0x30, + "subtracting two Addresses gives the distance between them"); + } + { + // A plain address has nothing to strip, whatever the platform. + Address plain(static_cast(0x0000000100002000)); + TEST_ASSERT_HEX_EQ(plain.stripped().toMachVMAddress(), 0x0000000100002000, + "stripping an unsigned address changes nothing"); + } +#if CPU(ARM64E) + { + // A pointer read out of a corpse arrives signed for the target's context, + // and must be reduced to the address it names before it is used as one. + void* raw = reinterpret_cast(static_cast(0x0000000100002000)); + void* signedPointer; + unsigned count = 0; + constexpr unsigned maxRetryCount = 10; + do { + signedPointer = ptrauth_sign_unauthenticated(raw, ptrauth_key_process_dependent_code, 0); + } while (signedPointer == raw && ++count <= maxRetryCount); + TEST_ASSERT(count <= maxRetryCount, "unable to generate PAC signed pointer for test"); + TEST_ASSERT_HEX_EQ(Address(signedPointer).stripped().toMachVMAddress(), + reinterpret_cast(raw), "stripping recovers the address a signed pointer names"); + } + { + // Top-byte-ignore and memory tagging both leave data in the top byte, which + // is not part of the address either. + Address tagged(static_cast(0x4200000100002000)); + TEST_ASSERT_HEX_EQ(tagged.stripped().toMachVMAddress(), 0x0000000100002000, + "stripping clears a tagged top byte"); + } +#endif +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.h b/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.h new file mode 100644 index 000000000000..2af264d1993e --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseAddressTest.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +void testAddress(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.cpp new file mode 100644 index 000000000000..cbc380b92fda --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseByteParserTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::ByteParser; + +void testByteParser() +{ + if (!beginSuite("ByteParser")) + return; + + { + Vector empty; + ByteParser parser(empty.span()); + TEST_ASSERT(!parser.consumeByte(), "consumeByte on an empty buffer yields nothing"); + TEST_ASSERT(!parser.consumeULEB128(), "consumeULEB128 on an empty buffer yields nothing"); + TEST_ASSERT(!parser.consumeCString(), "consumeCString on an empty buffer yields nothing"); + TEST_ASSERT_EQ(parser.position(), static_cast(0), "a failed read does not advance"); + } + { + Vector data { 0x11, 0x22 }; + ByteParser parser(data.span()); + auto first = parser.consumeByte(); + TEST_ASSERT(first && *first == 0x11, "consumeByte yields the first byte"); + TEST_ASSERT_EQ(parser.position(), static_cast(1), "consumeByte advances by one"); + auto second = parser.consumeByte(); + TEST_ASSERT(second && *second == 0x22, "consumeByte yields the next byte"); + TEST_ASSERT_EQ(parser.position(), static_cast(2), "consumeByte advances past the last byte"); + TEST_ASSERT(!parser.consumeByte(), "consumeByte stops at the end"); + } + { + // A parser may start part way in, which is how a node is read out of a trie. + Vector data { 0x11, 0x22, 0x33 }; + ByteParser parser(data.span(), 2); + auto value = parser.consumeByte(); + TEST_ASSERT(value && *value == 0x33, "a parser starts at the position it is given"); + TEST_ASSERT_EQ(parser.position(), static_cast(3), "a read advances from the given position"); + } + { + // A trie node's fields are ULEB128s read through a parser bounded to the whole + // trie but starting at the node, so decoding has to begin at that position and + // leave the cursor on the field that follows. + Vector data { 0x11, 0x22, 0xe5, 0x8e, 0x26, 0x33 }; + ByteParser parser(data.span(), 2); + auto value = parser.consumeULEB128(); + TEST_ASSERT(value && *value == 624485, "consumeULEB128 decodes from the position it is given"); + TEST_ASSERT_EQ(parser.position(), static_cast(5), "consumeULEB128 stops after the value it decoded"); + auto next = parser.consumeByte(); + TEST_ASSERT(next && *next == 0x33, "the byte after a decoded value is left for the next read"); + } + { + // A failed read rewinds to where the cursor was, which is not necessarily the + // start of the buffer. + Vector data { 0x11, 0x22, 0x80 }; + ByteParser parser(data.span(), 2); + TEST_ASSERT(!parser.consumeULEB128(), "a truncated ULEB128 is rejected wherever it starts"); + TEST_ASSERT_EQ(parser.position(), static_cast(2), "a failed read rewinds to the given position"); + } + + struct ULEBCase { + Vector bytes; + bool decodes; + uint64_t value; + const char* description; + }; + Vector ulebCases; + ulebCases.append({ { 0x00 }, true, 0, "zero" }); + ulebCases.append({ { 0x01 }, true, 1, "one" }); + ulebCases.append({ { 0x7f }, true, 127, "the largest one-byte value" }); + ulebCases.append({ { 0x80, 0x01 }, true, 128, "the smallest two-byte value" }); + ulebCases.append({ { 0xe5, 0x8e, 0x26 }, true, 624485, "a three-byte value" }); + ulebCases.append({ { 0x80, 0x80, 0x80, 0x00 }, true, 0, "zero padded with continuations" }); + ulebCases.append({ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }, true, + std::numeric_limits::max(), "the largest 64-bit value" }); + // Rejected: the top group carries bits that do not fit in 64. + ulebCases.append({ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02 }, false, 0, + "a value one bit too wide for 64 bits" }); + // Rejected: the shift would reach 64, which is undefined rather than merely large. + ulebCases.append({ { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01 }, false, 0, + "an encoding longer than 64 bits can hold" }); + ulebCases.append({ { 0x80 }, false, 0, "a value whose continuation runs off the end" }); + ulebCases.append({ { 0xff, 0xff }, false, 0, "a truncated multi-byte value" }); + + for (const ULEBCase& testCase : ulebCases) { + ByteParser parser(testCase.bytes.span()); + auto decoded = parser.consumeULEB128(); + if (!testCase.decodes) { + TEST_ASSERT(!decoded, testCase.description); + TEST_ASSERT_EQ(parser.position(), static_cast(0), testCase.description); + continue; + } + if (!decoded) { + TEST_ASSERT(decoded, testCase.description); + continue; + } + TEST_ASSERT_HEX_EQ(*decoded, testCase.value, testCase.description); + TEST_ASSERT_EQ(parser.position(), testCase.bytes.size(), testCase.description); + } + + { + Vector data { 'a', 'b', 0, 'c', 0 }; + ByteParser parser(data.span()); + auto first = parser.consumeCString(); + TEST_ASSERT(first && *first == "ab", "consumeCString yields the string"); + TEST_ASSERT_EQ(parser.position(), static_cast(3), "consumeCString consumes the terminator"); + auto second = parser.consumeCString(); + TEST_ASSERT(second && *second == "c", "consumeCString yields the following string"); + TEST_ASSERT_EQ(parser.position(), static_cast(5), "consumeCString consumes the second terminator"); + TEST_ASSERT(!parser.consumeCString(), "consumeCString stops at the end"); + } + { + Vector data { 0 }; + ByteParser parser(data.span()); + auto empty = parser.consumeCString(); + TEST_ASSERT(empty && empty->empty(), "an empty string is a string"); + TEST_ASSERT_EQ(parser.position(), static_cast(1), "an empty string still consumes its terminator"); + } + { + // A read that fails consumes nothing. + Vector unterminated { 'a', 'b' }; + ByteParser cstring(unterminated.span()); + TEST_ASSERT(!cstring.consumeCString(), "an unterminated string is rejected"); + TEST_ASSERT_EQ(cstring.position(), static_cast(0), + "a failed string read leaves the cursor where it was"); + + Vector truncated { 0x80, 0x80 }; + ByteParser uleb(truncated.span()); + TEST_ASSERT(!uleb.consumeULEB128(), "a truncated ULEB128 is rejected"); + TEST_ASSERT_EQ(uleb.position(), static_cast(0), + "a failed ULEB128 read leaves the cursor where it was"); + + // The failed read should not advance the cursor. Therefore, the 2nd read should succeed. + Vector lone { 0x80 }; + ByteParser retry(lone.span()); + TEST_ASSERT(!retry.consumeULEB128(), "a lone continuation byte is not a value"); + auto byte = retry.consumeByte(); + TEST_ASSERT(byte && *byte == 0x80, "a failed read leaves its bytes for another reader"); + } + { + Vector data { 0x11, 'a', 0 }; + for (size_t position : { data.size(), data.size() + 1, std::numeric_limits::max() }) { + ByteParser parser(data.span(), position); + TEST_ASSERT(!parser.consumeByte(), "consumeByte from beyond the end yields nothing"); + TEST_ASSERT(!parser.consumeULEB128(), "consumeULEB128 from beyond the end yields nothing"); + TEST_ASSERT(!parser.consumeCString(), "consumeCString from beyond the end yields nothing"); + TEST_ASSERT_EQ(parser.position(), position, "a failed read beyond the end does not move the cursor"); + } + } +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.h b/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.h new file mode 100644 index 000000000000..02c3681aee74 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseByteParserTest.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +void testByteParser(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.cpp new file mode 100644 index 000000000000..c13efc1b801d --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.cpp @@ -0,0 +1,811 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseExportsTrieTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::ExportsTrie; + +namespace { + +// Builds the bytes of a dyld exports trie, or of something that is not quite one. +// Emitting bytes rather than describing exports is deliberate: most of what is +// worth testing here is malformed, and could not be described any other way. +class TrieBytes { +public: + void byte(uint8_t value) { m_bytes.append(value); } + void bytes(std::span); + void uleb128(uint64_t); + + // A ULEB128 padded to a fixed width so that a forward reference can be + // patched once its target is known. Non-canonical but well formed: the + // padding bytes carry a continuation bit and no payload. + static constexpr unsigned fixedWidth = 3; + size_t uleb128Fixed(uint64_t); + void patchUleb128Fixed(size_t position, uint64_t); + + void cString(std::string_view); // With its terminator. + void string(std::string_view); // Without. + + size_t position() const { return m_bytes.size(); } + std::span span() const { return m_bytes.span(); } + Vector take() { return WTF::move(m_bytes); } + +private: + Vector m_bytes; +}; + +// The flags and payload of one terminal, as a trie encodes them. +struct TerminalSpec { + uint64_t flags { 0 }; + // The ULEB128s that follow the flags. What they mean depends on the flags: + // one offset for an ordinary export, a stub offset then a resolver offset + // for a stub-and-resolver, an ordinal for a re-export. + Vector values; + // Appended after the values, for a re-export's imported name. + std::string_view trailingString; + bool hasTrailingString { false }; +}; + +// A trie holding one export named "", so that a look up of "" reaches the +// terminal without walking any edge. Isolates terminal decoding from the walk. +Vector terminalOnlyTrie(const TerminalSpec&); + +// A trie whose root has one edge, `name`, leading to a terminal. +Vector singleExportTrie(std::string_view name, const TerminalSpec&); + +// A trie spelling one export across several edges, so a look up has to walk. +Vector chainedExportTrie(std::span edges, const TerminalSpec&); + +// An ordinary export at `offset` from the image's base. +TerminalSpec regularExport(uint64_t offset); + +void TrieBytes::bytes(std::span data) +{ + m_bytes.append(data); +} + +void TrieBytes::uleb128(uint64_t value) +{ + do { + uint8_t group = value & 0x7f; + value >>= 7; + if (value) + group |= 0x80; + m_bytes.append(group); + } while (value); +} + +size_t TrieBytes::uleb128Fixed(uint64_t value) +{ + size_t start = m_bytes.size(); + for (unsigned i = 0; i < fixedWidth; ++i) { + uint8_t group = (value >> (7 * i)) & 0x7f; + if (i + 1 < fixedWidth) + group |= 0x80; + m_bytes.append(group); + } + return start; +} + +void TrieBytes::patchUleb128Fixed(size_t position, uint64_t value) +{ + for (unsigned i = 0; i < fixedWidth; ++i) { + uint8_t group = (value >> (7 * i)) & 0x7f; + if (i + 1 < fixedWidth) + group |= 0x80; + m_bytes[position + i] = group; + } +} + +void TrieBytes::cString(std::string_view text) +{ + string(text); + m_bytes.append(0); +} + +void TrieBytes::string(std::string_view text) +{ + for (char character : text) + m_bytes.append(static_cast(character)); +} + +TerminalSpec regularExport(uint64_t offset) +{ + TerminalSpec spec; + spec.values.append(offset); + return spec; +} + +// The bytes a terminal node holds after its length: the flags, then whatever +// ULEB128s and string the flags call for. +static Vector terminalPayload(const TerminalSpec& spec) +{ + TrieBytes payload; + payload.uleb128(spec.flags); + for (uint64_t value : spec.values) + payload.uleb128(value); + if (spec.hasTrailingString) + payload.cString(spec.trailingString); + return payload.take(); +} + +// A node with a terminal and no children. +static void appendTerminalNode(TrieBytes& trie, const TerminalSpec& spec) +{ + Vector payload = terminalPayload(spec); + trie.uleb128(payload.size()); + trie.bytes(payload.span()); + trie.byte(0); // No children. +} + +Vector terminalOnlyTrie(const TerminalSpec& spec) +{ + TrieBytes trie; + appendTerminalNode(trie, spec); + return trie.take(); +} + +Vector chainedExportTrie(std::span edges, const TerminalSpec& spec) +{ + TrieBytes trie; + + // Every node but the last points at the one after it, whose position is not + // known until it has been emitted, so each reference is patched from behind. + Vector patchPositions; + for (std::string_view edge : edges) { + if (!patchPositions.isEmpty()) { + trie.patchUleb128Fixed(patchPositions.last(), trie.position()); + patchPositions.removeLast(); + } + trie.uleb128(0); // No terminal on the way down. + trie.byte(1); // One edge. + trie.cString(edge); + patchPositions.append(trie.uleb128Fixed(0)); + } + if (!patchPositions.isEmpty()) + trie.patchUleb128Fixed(patchPositions.last(), trie.position()); + appendTerminalNode(trie, spec); + return trie.take(); +} + +Vector singleExportTrie(std::string_view name, const TerminalSpec& spec) +{ + std::array edges { name }; + return chainedExportTrie(std::span(edges), spec); +} + +// A node's children count is one byte, so 255 edges is as wide as a node can be. +static constexpr unsigned maximumEdgeCount = 255; + +// The name of the `index`th edge of a fan-out trie. Two characters wide so that no +// edge is a prefix of another, which leaves exactly one of them matching a name. +static std::string fanOutEdgeName(unsigned index) +{ + return { static_cast('a' + index / 16), static_cast('a' + index % 16) }; +} + +// Distinct per edge, so that a walk landing on the wrong child is caught. +static constexpr uint64_t fanOutExportOffset(unsigned index) +{ + return 0x1000 + index; +} + +// A root with `edgeCount` edges, each leading to a terminal of its own. +static Vector fanOutTrie(unsigned edgeCount) +{ + TrieBytes trie; + trie.uleb128(0); // The root itself exports nothing. + trie.byte(static_cast(edgeCount)); + + // Each edge points at a node that has not been emitted yet, so the references + // are patched once their targets are laid down below. + Vector patchPositions; + for (unsigned index = 0; index < edgeCount; ++index) { + trie.cString(fanOutEdgeName(index)); + patchPositions.append(trie.uleb128Fixed(0)); + } + for (unsigned index = 0; index < edgeCount; ++index) { + trie.patchUleb128Fixed(patchPositions[index], trie.position()); + appendTerminalNode(trie, regularExport(fanOutExportOffset(index))); + } + return trie.take(); +} + +using Failure = ExportsTrie::Failure; +using Kind = ExportsTrie::Export::Kind; + +} // anonymous namespace + +// A node carrying both a terminal and one edge, which is how a trie holds an +// export whose name is a prefix of another export's name. +static Vector prefixAndChildTrie(std::string_view rootEdge, const TerminalSpec& atRootEdge, + std::string_view childEdge, const TerminalSpec& atChild) +{ + TrieBytes trie; + trie.uleb128(0); // The root itself exports nothing. + trie.byte(1); + trie.cString(rootEdge); + size_t rootEdgePatch = trie.uleb128Fixed(0); + + trie.patchUleb128Fixed(rootEdgePatch, trie.position()); + TrieBytes payload; + payload.uleb128(atRootEdge.flags); + for (uint64_t value : atRootEdge.values) + payload.uleb128(value); + Vector payloadBytes = payload.take(); + trie.uleb128(payloadBytes.size()); + trie.bytes(payloadBytes.span()); + trie.byte(1); + trie.cString(childEdge); + size_t childPatch = trie.uleb128Fixed(0); + + trie.patchUleb128Fixed(childPatch, trie.position()); + TrieBytes childPayload; + childPayload.uleb128(atChild.flags); + for (uint64_t value : atChild.values) + childPayload.uleb128(value); + Vector childPayloadBytes = childPayload.take(); + trie.uleb128(childPayloadBytes.size()); + trie.bytes(childPayloadBytes.span()); + trie.byte(0); + + return trie.take(); +} + +static void testFoundExports() +{ + { + Vector trie = singleExportTrie("_foo", regularExport(0x1234)); + auto found = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(found, "an exported name is found"); + if (found) { + TEST_ASSERT(found->kind == Kind::Regular, "an ordinary export is Regular"); + TEST_ASSERT_HEX_EQ(found->value, 0x1234, "an ordinary export yields its offset"); + } + } + { + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE; + spec.values.append(0xdeadbeef); + Vector trie = singleExportTrie("_absolute", spec); + auto found = ExportsTrie::lookUp(trie.span(), "_absolute"); + TEST_ASSERT(found, "an absolute export is found"); + if (found) { + TEST_ASSERT(found->kind == Kind::Absolute, "an absolute export is Absolute"); + TEST_ASSERT_HEX_EQ(found->value, 0xdeadbeef, "an absolute export yields the address itself"); + } + } + { + // A weak definition is still an ordinary export; the flag sits outside the + // kind mask and must not disturb it. + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION | EXPORT_SYMBOL_FLAGS_KIND_REGULAR; + spec.values.append(0x40); + Vector trie = singleExportTrie("_weak", spec); + auto found = ExportsTrie::lookUp(trie.span(), "_weak"); + TEST_ASSERT(found, "a weak definition is found"); + if (found) { + TEST_ASSERT(found->kind == Kind::Regular, "a weak definition is Regular"); + TEST_ASSERT_HEX_EQ(found->value, 0x40, "a weak definition yields its offset"); + } + } + { + // Per , a stub-and-resolver terminal holds two ULEB128s: + // the stub offset and then the resolver offset. The stub is the address + // the symbol resolves to; the resolver is only how a lazy binding finds it. + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER | EXPORT_SYMBOL_FLAGS_KIND_REGULAR; + spec.values.append(0x1000); // Stub offset. + spec.values.append(0x2000); // Resolver offset. + Vector trie = singleExportTrie("_resolved", spec); + auto found = ExportsTrie::lookUp(trie.span(), "_resolved"); + TEST_ASSERT(found, "a stub-and-resolver export is found"); + if (found) { + TEST_ASSERT(found->kind == Kind::Regular, "a stub-and-resolver export is Regular"); + TEST_ASSERT_HEX_EQ(found->value, 0x1000, "a stub-and-resolver export yields the stub offset"); + } + } + { + // The highest defined flag bit. It carries no payload of its own, so a + // terminal that sets it still decodes; nothing in dyld, ld or cctools reads + // it, which is why it must not be mistaken for an unknown bit. + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER | EXPORT_SYMBOL_FLAGS_KIND_REGULAR; + spec.values.append(0x50); + Vector trie = singleExportTrie("_staticResolver", spec); + auto found = ExportsTrie::lookUp(trie.span(), "_staticResolver"); + TEST_ASSERT(found, "an export with the highest defined flag bit is found"); + if (found) { + TEST_ASSERT(found->kind == Kind::Regular, "a static-resolver export is Regular"); + TEST_ASSERT_HEX_EQ(found->value, 0x50, "a static-resolver export yields its offset"); + } + } + { + // A terminal may declare more room than its flags and offset need. The spare + // room is not part of the offset, and the export still resolves. + TrieBytes builder; + builder.uleb128(4); // Two bytes more than the payload below uses. + builder.uleb128(0); // Flags: an ordinary export. + builder.uleb128(0x7f); // Offset. + builder.byte(0); // Spare terminal byte. + builder.byte(0); // Spare terminal byte. + builder.byte(0); // No children. + Vector trie = builder.take(); + auto found = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(found, "a terminal with room to spare still resolves"); + if (found) + TEST_ASSERT_HEX_EQ(found->value, 0x7f, "spare terminal room is not read as the offset"); + } + { + // A look up of "" reaches the root's own terminal without walking an edge. + Vector trie = terminalOnlyTrie(regularExport(0x99)); + auto found = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(found, "a terminal at the root is found"); + if (found) + TEST_ASSERT_HEX_EQ(found->value, 0x99, "a terminal at the root yields its offset"); + } + { + // Real tries spread a name over several edges, so the walk has to cross + // more than one node to reach the terminal. + std::array edges { "_f", "oo", "bar" }; + Vector trie = chainedExportTrie(std::span(edges), regularExport(0x77)); + auto found = ExportsTrie::lookUp(trie.span(), "_foobar"); + TEST_ASSERT(found, "a name spread over several edges is found"); + if (found) + TEST_ASSERT_HEX_EQ(found->value, 0x77, "a multi-edge name yields its offset"); + + auto prefix = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!prefix && prefix.error() == Failure::Absent, + "a prefix of a multi-edge name is absent"); + auto extension = ExportsTrie::lookUp(trie.span(), "_foobarbaz"); + TEST_ASSERT(!extension && extension.error() == Failure::Absent, + "an extension of a multi-edge name is absent"); + } + { + // "_foo" and "_foobar" both exported: the shorter one lives on a node that + // also has children, so a terminal must not end the walk when name is left. + Vector trie = prefixAndChildTrie("_foo", regularExport(0x10), "bar", regularExport(0x20)); + auto shorter = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(shorter, "the shorter of two nested names is found"); + if (shorter) + TEST_ASSERT_HEX_EQ(shorter->value, 0x10, "the shorter name yields its own offset"); + auto longer = ExportsTrie::lookUp(trie.span(), "_foobar"); + TEST_ASSERT(longer, "the longer of two nested names is found"); + if (longer) + TEST_ASSERT_HEX_EQ(longer->value, 0x20, "the longer name yields its own offset"); + TEST_ASSERT(!ExportsTrie::lookUp(trie.span(), "_foobaz"), "a name that diverges is not found"); + } + { + // A node's children count is a byte rather than a ULEB128. Decoded as one, a + // count of 255 carries a continuation bit, so it would swallow the first + // character of the edge behind it: the count comes out far too large and that + // edge is read from the wrong byte. 255 edges is the widest a node can be, and + // reaching the last of them needs the walk to scan past every edge ahead of it. + Vector trie = fanOutTrie(maximumEdgeCount); + for (unsigned index : { 0u, maximumEdgeCount / 2, maximumEdgeCount - 1 }) { + auto found = ExportsTrie::lookUp(trie.span(), fanOutEdgeName(index)); + TEST_ASSERT(found, "an export is found among 255 edges"); + if (found) { + TEST_ASSERT_HEX_EQ(found->value, fanOutExportOffset(index), + "each of 255 edges leads to its own export"); + } + } + + // Nothing matches, so the walk has to scan all 255 edges and end. + auto absent = ExportsTrie::lookUp(trie.span(), "zz"); + TEST_ASSERT(!absent && absent.error() == Failure::Absent, + "a name matching none of 255 edges is Absent"); + } +} + +static void testClassifiedFailures() +{ + { + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_REEXPORT | EXPORT_SYMBOL_FLAGS_KIND_REGULAR; + spec.values.append(1); // Library ordinal. + spec.trailingString = "_other"; + spec.hasTrailingString = true; + Vector trie = singleExportTrie("_reexported", spec); + auto result = ExportsTrie::lookUp(trie.span(), "_reexported"); + TEST_ASSERT(!result && result.error() == Failure::ReExport, + "a re-exported name reports ReExport rather than being absent"); + } + { + TerminalSpec spec; + spec.flags = EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL; + spec.values.append(0x30); + Vector trie = singleExportTrie("_threadLocal", spec); + auto result = ExportsTrie::lookUp(trie.span(), "_threadLocal"); + TEST_ASSERT(!result && result.error() == Failure::UnsupportedKind, + "a thread-local reports UnsupportedKind: its address differs per thread"); + } + { + // The one value the kind mask can hold that Mach-O does not define. A kind + // this code does not know cannot be read as an address. + TerminalSpec spec; + spec.flags = 0x03; + spec.values.append(0x30); + Vector trie = singleExportTrie("_unknownKind", spec); + auto result = ExportsTrie::lookUp(trie.span(), "_unknownKind"); + TEST_ASSERT(!result && result.error() == Failure::UnsupportedKind, + "an unrecognized kind reports UnsupportedKind"); + } + { + Vector trie = singleExportTrie("_foo", regularExport(0x1234)); + auto missing = ExportsTrie::lookUp(trie.span(), "_bar"); + TEST_ASSERT(!missing && missing.error() == Failure::Absent, + "a name with no matching edge is Absent"); + auto shortName = ExportsTrie::lookUp(trie.span(), "_fo"); + TEST_ASSERT(!shortName && shortName.error() == Failure::Absent, + "a name shorter than the edge is Absent"); + auto emptyName = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!emptyName && emptyName.error() == Failure::Absent, + "the empty name is Absent when the root exports nothing"); + } + { + // A node with neither a terminal nor children ends the walk without an answer. + TrieBytes builder; + builder.uleb128(0); + builder.byte(0); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Absent, "a childless root is Absent"); + } +} + +static void testMalformedTries() +{ + { + Vector empty; + auto result = ExportsTrie::lookUp(empty.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, "an empty trie is malformed"); + } + { + Vector trie { 0x80 }; // A terminal length that never ends. + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a truncated terminal length is malformed"); + } + { + // A terminal claiming more bytes than the trie has left. Rejecting this is + // what keeps the children position inside the buffer. + Vector trie { 0x7f }; + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a terminal longer than the trie is malformed"); + } + { + // A terminal length so large that adding it to the position would wrap. + TrieBytes builder; + builder.uleb128(std::numeric_limits::max()); + builder.byte(0); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a terminal length that would wrap the position is malformed"); + } + { + Vector trie { 0x01, 0x80 }; // Terminal of one byte, holding half a ULEB128. + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, "truncated flags are malformed"); + } + { + Vector trie { 0x01, 0x00 }; // Flags say an ordinary export, but no offset follows. + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "an export with no offset is malformed"); + } + { + // Flags promise a stub offset that the trie does not hold. + TrieBytes builder; + TrieBytes payload; + payload.uleb128(EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER | EXPORT_SYMBOL_FLAGS_KIND_REGULAR); + Vector payloadBytes = payload.take(); + builder.uleb128(payloadBytes.size()); + builder.bytes(payloadBytes.span()); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a stub-and-resolver export with no offsets is malformed"); + } + { + // Only six flag bits are defined. An unknown one may carry a ULEB128 ahead of + // the address, so the offset that follows it cannot be trusted to be one. + TerminalSpec spec; + spec.flags = 0x40; + spec.values.append(0x42); + Vector trie = singleExportTrie("_unknownFlag", spec); + auto result = ExportsTrie::lookUp(trie.span(), "_unknownFlag"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a terminal with an unknown flag bit is malformed"); + } + { + // A terminal that declares only its flags holds no offset. Reading one anyway + // would take the children count that follows it as the symbol's address. + TrieBytes builder; + builder.uleb128(1); // Terminal length: room for the flags alone. + builder.uleb128(0); // Flags: an ordinary export, which needs an offset... + builder.byte(2); // ...but this is the children count, not one. + builder.cString("a"); + builder.uleb128(0); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a terminal that ends before its offset is malformed"); + } + { + // The offset's encoding runs off the end of the terminal, so completing it + // would take a byte belonging to the children. + TrieBytes builder; + builder.uleb128(2); // Terminal length: the flags and one offset byte. + builder.uleb128(0); // Flags. + builder.byte(0x80); // First byte of a two-byte offset... + builder.byte(0x01); // ...whose second byte lies outside the terminal. + builder.byte(0); // No children. + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), ""); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "an offset whose encoding leaves the terminal is malformed"); + } + { + // The children count sits past the end of the trie. + Vector trie { 0x00 }; + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a missing children count is malformed"); + } + { + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.string("_foo"); // No terminator. + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "an unterminated edge is malformed"); + } + { + // An empty edge would match anything and consume none of the name, which is + // what would let a walk run forever. + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.cString(""); + builder.uleb128(0); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, "an empty edge is malformed"); + } + { + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.cString("_foo"); + builder.byte(0x80); // A child offset that never ends. + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a truncated child offset is malformed"); + } + { + // An edge leading outside the trie. + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.cString("_foo"); + builder.uleb128(1000); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result && result.error() == Failure::Malformed, + "a child offset past the end of the trie is malformed"); + } + { + // An edge leading into the middle of the node it came from. Whatever that + // decodes to, it must be an answer rather than a crash or a hang. + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.cString("_foo"); + builder.uleb128(2); + Vector trie = builder.take(); + auto result = ExportsTrie::lookUp(trie.span(), "_foo"); + TEST_ASSERT(!result, "a child offset into the middle of a node yields no export"); + } + { + // A trie truncated part way through a node it claims to hold. The last byte + // is the terminal node's children count, which a look up that ends at that + // terminal never reads, so removing only that byte still resolves; every + // shorter prefix cuts into the terminal itself and must not. + Vector trie = singleExportTrie("_foo", regularExport(0x1234)); + for (size_t length = 1; length + 1 < trie.size(); ++length) { + auto result = ExportsTrie::lookUp(trie.span().first(length), "_foo"); + TEST_ASSERT(!result, "a truncated trie yields no export"); + } + } +} + +static void testWalkIsBounded() +{ + // A node whose only edge leads back to itself. The walk may only follow an edge + // by consuming at least one character of the name, so it has to end even though + // the trie describes a cycle. Without that property this test would not return. + TrieBytes builder; + builder.uleb128(0); + builder.byte(1); + builder.cString("a"); + builder.uleb128(0); // Back to the root. + Vector trie = builder.take(); + + std::string name(20000, 'a'); + auto result = ExportsTrie::lookUp(trie.span(), name); + TEST_ASSERT(!result, "a cyclic trie yields no export"); + + // The same cycle reached with a name it cannot consume. + auto other = ExportsTrie::lookUp(trie.span(), "b"); + TEST_ASSERT(!other && other.error() == Failure::Absent, "a cycle whose edge does not match is Absent"); +} + +void testExportsTrie() +{ + if (!beginSuite("ExportsTrie")) + return; + + testFoundExports(); + testClassifiedFailures(); + testMalformedTries(); + testWalkIsBounded(); +} + +// A small deterministic generator, so that a failure can be reproduced from the +// seed the run reports. +class Random { +public: + explicit Random(uint64_t seed) + : m_state(seed ? seed : 0x9e3779b97f4a7c15ull) + { + } + + uint64_t next() + { + m_state ^= m_state >> 12; + m_state ^= m_state << 25; + m_state ^= m_state >> 27; + return m_state * 0x2545f4914f6cdd1dull; + } + + uint32_t below(uint32_t bound) { return bound ? static_cast(next() % bound) : 0; } + +private: + uint64_t m_state; +}; + +static Atomic fuzzIteration; +static Atomic fuzzFinished; + +static void* fuzzWatchdog(void*) +{ + uint64_t lastSeen = 0; + unsigned stalledPolls = 0; + static constexpr unsigned pollIntervalUsec = 250 * 1000; + static constexpr unsigned stallLimitPolls = 40; // Ten seconds. + + while (!fuzzFinished.load()) { + usleep(pollIntervalUsec); + uint64_t current = fuzzIteration.load(); + if (current != lastSeen) { + lastSeen = current; + stalledPolls = 0; + continue; + } + if (++stalledPolls < stallLimitPolls) + continue; + // The decoder promises to bound its work on any input. A stall means it + // does not, so crash here rather than let the run hang: a report with a + // stack in the decoder says far more than a timeout does. + dataLogLn("FAIL: exports trie look up did not finish on fuzz iteration ", lastSeen); + CRASH(); + } + return nullptr; +} + +void fuzzExportsTrie(uint64_t seed, unsigned iterations) +{ + if (!beginSuite("ExportsTrie fuzz")) + return; + dataLogLn(" seed ", RawHex(seed), ", ", iterations, " iterations"); + + Random random(seed); + fuzzIteration.store(0); + fuzzFinished.store(false); + + pthread_t watchdog { }; + bool watching = !pthread_create(&watchdog, nullptr, fuzzWatchdog, nullptr); + TEST_ASSERT(watching, "the fuzz watchdog started"); + + Vector valid = singleExportTrie("_foo", regularExport(0x1234)); + std::array names { "_foo", "_foobar", "_f", "", "_bar", "_fop" }; + + for (unsigned iteration = 0; iteration < iterations; ++iteration) { + fuzzIteration.store(iteration + 1); + + Vector trie; + if (random.below(4)) { + // Mostly near-valid tries: those reach further into the decoder than + // noise does, because their early fields still make sense. + trie = valid; + unsigned mutations = 1 + random.below(6); + for (unsigned mutation = 0; mutation < mutations; ++mutation) + trie[random.below(static_cast(trie.size()))] = static_cast(random.next()); + } else { + unsigned length = random.below(64); + for (unsigned index = 0; index < length; ++index) + trie.append(static_cast(random.next())); + } + + std::string generatedName; + std::string_view name; + if (random.below(4)) + name = names[random.below(names.size())]; + else { + unsigned length = random.below(12); + for (unsigned index = 0; index < length; ++index) + generatedName += static_cast('_' + random.below(48)); + name = generatedName; + } + + auto result = ExportsTrie::lookUp(trie.span(), name); + // Noise is allowed to decode as an export. What is not allowed is an + // export of a kind the caller cannot act on. + if (result) { + TEST_ASSERT(result->kind == Kind::Regular || result->kind == Kind::Absolute, + "a decoded export has a kind the caller understands"); + } + } + + fuzzFinished.store(true); + if (watching) + pthread_join(watchdog, nullptr); +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.h b/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.h new file mode 100644 index 000000000000..29e8bc6b4f8f --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseExportsTrieTest.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include + +namespace JSCToolsTest { + +void testExportsTrie(); + +// Feeds mutated and random tries to the decoder. A trie out of a corpse is +// untrusted, and the decoder promises to bound its work on any input, which only +// a run over inputs nobody wrote can really check. +void fuzzExportsTrie(uint64_t seed, unsigned iterations); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.cpp new file mode 100644 index 000000000000..445ceb9d5b20 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseProcessTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::Process; + +// A pid that is certainly not in use: a child that has been reaped. Returns 0 if +// no child could be made. +static pid_t reapedChildPid() +{ + pid_t child = fork(); + if (!child) + _exit(0); + if (child < 0) + return 0; + int status = 0; + if (waitpid(child, &status, 0) != child) + return 0; + return child; +} + +#if CPU(ARM64) +// Launches /bin/sh as x86_64, which on Apple silicon means under translation. +// Returns 0 if this machine cannot run x86_64 code. +static pid_t spawnTranslatedChild() +{ + posix_spawnattr_t attributes; + if (posix_spawnattr_init(&attributes)) + return 0; + + cpu_type_t preference = CPU_TYPE_X86_64; + size_t counted = 0; + posix_spawnattr_setbinpref_np(&attributes, 1, &preference, &counted); + + char* const arguments[] = { + const_cast("/bin/sh"), + const_cast("-c"), + const_cast("sleep 30"), + nullptr + }; + pid_t child = 0; + int error = posix_spawn(&child, "/bin/sh", nullptr, &attributes, arguments, nullptr); + posix_spawnattr_destroy(&attributes); + + if (error || counted != 1) + return 0; + return child; +} +#endif // CPU(ARM64) + +void testProcess() +{ + if (!beginSuite("Process")) + return; + + { + RefPtr process = Process::create(getpid()); + TEST_ASSERT(!process->isAttached(), "a new Process is not attached"); + TEST_ASSERT_EQ(process->pid(), getpid(), "a Process keeps the pid it was given"); + + TEST_ASSERT(process->attach(), "attaching to this process succeeds"); + TEST_ASSERT(process->isAttached(), "attaching leaves the Process attached"); + TEST_ASSERT(process->holdsLiveTask(), "the task port names this very process"); + TEST_ASSERT(process->attach(), "attaching an already attached Process succeeds"); + + process->detach(); + TEST_ASSERT(!process->isAttached(), "detaching releases the task port"); + TEST_ASSERT(!process->holdsLiveTask(), "a detached Process holds no task"); + + TEST_ASSERT(process->attach(), "a detached Process can attach again"); + process->detach(); + process->detach(); + TEST_ASSERT(!process->isAttached(), "detaching twice is harmless"); + } + { + // Attaching takes a send right to the target's task port, and every path out of + // an attach has to give it back. Attaching to this very process yields the name + // this task already holds for itself, so the kernel adds a reference to that + // name rather than handing out a new one: a right that is never given back + // shows up in the reference count and not in the size of the name space. + unsigned namesBefore = machPortNameCount(); + mach_port_t port = MACH_PORT_NULL; + unsigned refsAttached = 0; + { + RefPtr process = Process::create(getpid()); + TEST_ASSERT(process->attach(), "attaching to this process succeeds"); + if (process->isAttached()) { + port = process->taskPort(); + refsAttached = machPortSendRightCount(port); + TEST_ASSERT(refsAttached, "an attached Process holds a send right to the task port"); + + process->attach(); + TEST_ASSERT_EQ(machPortSendRightCount(port), refsAttached, + "attaching an attached Process takes no further send right"); + + process->detach(); + TEST_ASSERT_EQ(machPortSendRightCount(port), refsAttached - 1, + "detaching gives the send right back"); + process->detach(); + TEST_ASSERT_EQ(machPortSendRightCount(port), refsAttached - 1, + "detaching twice gives back only what one attach took"); + + process->attach(); // Left attached, so the destructor has to release it. + } + } + if (refsAttached) { + TEST_ASSERT_EQ(machPortSendRightCount(port), refsAttached - 1, + "destroying an attached Process gives its send right back"); + TEST_ASSERT_EQ(machPortNameCount(), namesBefore, + "attaching and detaching leaves no port name behind"); + } + } + { + pid_t gone = reapedChildPid(); + if (!gone) + TEST_ASSERT(gone, "a child could be forked and reaped"); + else { + dataLogLn(" (the next line is the failure this test asks for)"); + unsigned namesBefore = machPortNameCount(); + RefPtr process = Process::create(gone); + TEST_ASSERT(!process->attach(), "attaching to a process that has exited fails"); + TEST_ASSERT(!process->isAttached(), "a failed attach leaves the Process unattached"); + TEST_ASSERT_EQ(machPortNameCount(), namesBefore, "a failed attach leaves no port name behind"); + } + } + { + RefPtr process = Process::create(getpid()); + TEST_ASSERT(!process->isTranslated(), "this process does not run under translation"); + // Answering this needs no task port, only the pid. + TEST_ASSERT(!process->isAttached(), "asking about translation does not attach"); + } + { + RefPtr initProcess = Process::create(1); + TEST_ASSERT(!initProcess->isTranslated(), "launchd does not run under translation"); + } + { + pid_t gone = reapedChildPid(); + if (gone) { + RefPtr process = Process::create(gone); + TEST_ASSERT(!process->isTranslated(), "a process that has exited is not translated"); + } + } +#if CPU(ARM64) + { + pid_t translated = spawnTranslatedChild(); + if (!translated) + skipSuite("Process translation", "this machine cannot run x86_64 code"); + else { + RefPtr process = Process::create(translated); + TEST_ASSERT(process->isTranslated(), "a process running x86_64 code is translated"); + kill(translated, SIGKILL); + int status = 0; + waitpid(translated, &status, 0); + } + } +#endif // CPU(ARM64) +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.h b/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.h new file mode 100644 index 000000000000..1245c56e1e07 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseProcessTest.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +void testProcess(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.cpp new file mode 100644 index 000000000000..813b24717cd7 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseRegionTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::Address; +using JSC::Corpse::Region; + +void testRegion() +{ + if (!beginSuite("Region")) + return; + + size_t pageSize = static_cast(getpagesize()); + static constexpr size_t mappedPages = 5; + static constexpr size_t writtenPages = 2; + static constexpr size_t readPages = 1; // Exclusive of writtenPages. + + // The test scratch area is seven pages, with the first and last given back (holes), so + // that the five in the middle are a region of known size with a hole on either side. + // In this test, we'll check on those hole pages being holes. Hence, we need for them to + // stay unmapped. + // + // Unfortunately, bmalloc or other heaps, when expanding, may consume the lower unmapped + // page, and put it to use. This breaks our reliance on it being unmapped. So, we'll + // precede the test scratch area with a runway of 10 unmapped pages. This gives any heap + // some room to grow into without picking off our hole pages. + static constexpr size_t runwayPaddingPages = 10; + static constexpr size_t lowerSentinelPage = runwayPaddingPages; + static constexpr size_t holeBelowRegion = lowerSentinelPage + 1; + static constexpr size_t holeAboveRegion = holeBelowRegion + mappedPages + 1; + static constexpr size_t upperSentinelPage = holeAboveRegion + 1; + static constexpr size_t reservationPages = upperSentinelPage + 1; + + size_t reservationSize = reservationPages * pageSize; + void* reservation = mmap(nullptr, reservationSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (reservation == MAP_FAILED) { + TEST_ASSERT(false, "the required test VA should be mappable"); + return; + } + auto addressAt = [&](size_t pageIndex) { + return reinterpret_cast(reservation) + pageIndex * pageSize; + }; + auto unmapPages = [&](size_t pageIndex, size_t pageCount) { + munmap(reinterpret_cast(addressAt(pageIndex)), pageCount * pageSize); + }; + unmapPages(0, runwayPaddingPages); + unmapPages(holeBelowRegion, 1); + unmapPages(holeAboveRegion, 1); + + uintptr_t base = addressAt(holeBelowRegion + 1); + for (size_t page = 0; page < writtenPages; ++page) + *reinterpret_cast(base + page * pageSize) = 1; // Touch with write. + for (size_t page = writtenPages; page < writtenPages + readPages; ++page) + (void)*reinterpret_cast(base + page * pageSize); // Touch with read. + + // Gives back everything this test still holds: the region and the two sentinels. + // The runwayPaddingPages are already unmapped. + auto unmapPagesStillHeld = [&]() { + unmapPages(lowerSentinelPage, 1); + unmapPages(holeBelowRegion + 1, mappedPages); + unmapPages(upperSentinelPage, 1); + }; + + SelfSnapshot self; + if (!self.isValid()) { + unmapPagesStillHeld(); + return; + } + mach_port_t corpsePort = self.snapshot().corpsePort(); + + { + auto region = Region::findContaining(corpsePort, Address(static_cast(base))); + TEST_ASSERT(region, "the region holding a known mapping is found"); + if (region) { + TEST_ASSERT_HEX_EQ(region->base().toMachVMAddress(), base, "the region starts where the mapping does"); + TEST_ASSERT_EQ(region->size(), mappedPages * pageSize, "the region is as large as the mapping"); + TEST_ASSERT_HEX_EQ(region->end().toMachVMAddress(), base + mappedPages * pageSize, + "the region ends where the mapping does"); + TEST_ASSERT_EQ(region->pageCount(), + static_cast(mappedPages * pageSize / vm_kernel_page_size), + "the region holds as many pages as were mapped"); + TEST_ASSERT(region->contains(region->base()), "a region contains its first byte"); + TEST_ASSERT(region->contains(region->end() - 1), "a region contains its last byte"); + TEST_ASSERT(!region->contains(region->end()), "a region does not contain the byte past its end"); + TEST_ASSERT(!region->contains(region->base() - 1), "a region does not contain the byte before it"); + + uint64_t accessedKernelPages = + static_cast((writtenPages + readPages) * pageSize / vm_kernel_page_size); + TEST_ASSERT_EQ(region->residentPageCount(), accessedKernelPages, + "the pages that were accessed are the resident ones"); + + // Dirty does not mean written: an anonymous page has no pager to be re-read + // from, so it counts as dirty from the moment a fault creates it, whether + // that fault was a write or a read. The page that was only read is dirty in + // most runs but not all, so the written pages are what can be counted on. + uint64_t writtenKernelPages = static_cast(writtenPages * pageSize / vm_kernel_page_size); + TEST_ASSERT(region->dirtyPageCount() >= writtenKernelPages + && region->dirtyPageCount() <= accessedKernelPages, + "every page that was written is dirty and no page that was never accessed is"); + } + } + { + // An address in the middle of the mapping still finds the whole region. + auto region = Region::findContaining(corpsePort, + Address(static_cast(base + pageSize + 16))); + TEST_ASSERT(region, "an address inside the mapping finds the region"); + if (region) + TEST_ASSERT_HEX_EQ(region->base().toMachVMAddress(), base, "any address in a region finds its base"); + } + { + // The kernel reports the region at or above the address it is asked about, + // so a hole must be reported as a hole rather than as the region above it. + auto region = Region::findContaining(corpsePort, + Address(static_cast(addressAt(holeBelowRegion)))); + TEST_ASSERT(!region, "an address in an unmapped hole finds no region"); + } + { + // The same question asked from the other side. An address in this hole sits past + // the end of the region below it, which must not be reported as containing it. + auto region = Region::findContaining(corpsePort, + Address(static_cast(addressAt(holeAboveRegion)))); + TEST_ASSERT(!region, "an address in the hole above a region finds no region"); + } + { + // The shared cache is mapped as a submap, which the search has to descend + // into before it can describe what is actually there. A function's address + // arrives signed on arm64e, and is an address only once stripped. + Address inSharedCache = Address(reinterpret_cast(&memcpy)).stripped(); + auto region = Region::findContaining(corpsePort, inSharedCache); + TEST_ASSERT(region, "an address in the shared cache finds a region"); + if (region) + TEST_ASSERT(region->size(), "a shared cache region has a size"); + } + + unmapPagesStillHeld(); +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.h b/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.h new file mode 100644 index 000000000000..b2c14df1c4db --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseRegionTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +// Takes a corpse of the running test itself, so that everything the corpse +// reports can be checked against what this process already knows. + +void testRegion(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.cpp new file mode 100644 index 000000000000..92a922f913b3 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseSnapshotTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::Process; +using JSC::Corpse::Snapshot; + +void testSnapshot() +{ + if (!beginSuite("Snapshot")) + return; + + RefPtr process = Process::create(getpid()); + if (!process->attach()) { + TEST_ASSERT(false, "attaching to this process succeeds"); + return; + } + + unsigned firstId = 0; + { + Snapshot snapshot(process); + TEST_ASSERT(snapshot.isValid(), "a snapshot of this process is valid"); + TEST_ASSERT(MACH_PORT_VALID(snapshot.corpsePort()), "a valid snapshot holds a corpse port"); + TEST_ASSERT(snapshot.process() == process.get(), "a snapshot keeps the process it came from"); + firstId = snapshot.id(); + TEST_ASSERT(firstId, "a snapshot has an identifier"); + + Snapshot second(process); + TEST_ASSERT(second.isValid(), "a second snapshot of the same process is valid"); + TEST_ASSERT(second.id() > firstId, "identifiers increase"); + TEST_ASSERT(second.corpsePort() != snapshot.corpsePort(), + "two snapshots hold two different corpses"); + } + { + // The two above are gone; their identifiers must not come back. + Snapshot later(process); + TEST_ASSERT(later.id() > firstId + 1, "identifiers are not reused after a snapshot is destroyed"); + } + { + RefPtr unattached = Process::create(getpid()); + Snapshot snapshot(unattached); + TEST_ASSERT(!snapshot.isValid(), "a snapshot of an unattached process is invalid"); + TEST_ASSERT(snapshot.threads().isEmpty(), "an invalid snapshot reports no threads"); + TEST_ASSERT(!snapshot.symbol("g_config"), "an invalid snapshot resolves no symbol"); + } + { + RefPtr none; + Snapshot snapshot(none); + TEST_ASSERT(!snapshot.isValid(), "a snapshot with no process is invalid"); + } + { + Snapshot snapshot(process); + TEST_ASSERT(!snapshot.symbol(nullptr), "an unnamed symbol resolves to nothing"); + TEST_ASSERT(!snapshot.symbol(""), "an empty symbol name resolves to nothing"); + } + + { + // A corpse and the threads read out of it are Mach ports. Taking many + // snapshots must not leave any of them behind. + static constexpr unsigned rounds = 100; + unsigned before = machPortNameCount(); + for (unsigned round = 0; round < rounds; ++round) { + Snapshot snapshot(process); + if (!snapshot.isValid()) + continue; + snapshot.threads(); + } + unsigned after = machPortNameCount(); + // A handful of names may come and go for reasons of their own; a leak of + // one port per round would be a hundred. + static constexpr unsigned allowedDrift = 8; + TEST_ASSERT(after <= before + allowedDrift, "taking and dropping snapshots leaks no Mach port"); + if (after > before + allowedDrift) + dataLogLn(" port names before ", before, ", after ", after, ", over ", rounds, " snapshots"); + } +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.h b/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.h new file mode 100644 index 000000000000..4a0b7759f219 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseSnapshotTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +// Takes a corpse of the running test itself, so that everything the corpse +// reports can be checked against what this process already knows. + +void testSnapshot(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.cpp new file mode 100644 index 000000000000..8bb461be59e2 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseSymbolTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Exists in this binary but is not exported, so an exports trie cannot see it. +// A look up must report that rather than find it some other way. +extern "C" __attribute__((visibility("hidden"))) int jscToolsTestHiddenGlobal; +int jscToolsTestHiddenGlobal = 42; + +namespace JSCToolsTest { + +using JSC::Corpse::Address; +using JSC::Corpse::Snapshot; +using JSC::Corpse::Symbol; + +// A symbol resolved out of a corpse of this very process must land on the same +// address this process would use, because the corpse is a copy of this address +// space. That makes every look up below checkable against ground truth. +void testSymbol() +{ + if (!beginSuite("Symbol")) + return; + + SelfSnapshot self; + if (!self.isValid()) + return; + Snapshot& snapshot = self.snapshot(); + + { + // A data symbol exported by the JavaScriptCore framework: an image that is + // not in the shared cache, so this checks the slide from __TEXT's link-time + // address to where the image actually landed. + auto expected = reinterpret_cast(WebConfig::g_config); + Address found = snapshot.symbol("g_config"); + TEST_ASSERT(found, "a symbol exported by JavaScriptCore is found"); + TEST_ASSERT_HEX_EQ(found.toMachVMAddress(), expected, + "g_config resolves to the address this process uses for it"); + } + { + // A function in the shared cache, where __LINKEDIT is shared between images + // and the trie is reached by a different route. + void* expected = dlsym(RTLD_DEFAULT, "malloc"); + TEST_ASSERT(expected, "malloc can be looked up locally"); + Address found = snapshot.symbol("malloc"); + TEST_ASSERT(found, "a symbol exported by a shared cache image is found"); + // A function pointer arrives signed on arm64e; only the address it names is + // being compared here. + TEST_ASSERT_HEX_EQ(found.stripped().toMachVMAddress(), + Address(expected).stripped().toMachVMAddress(), + "malloc resolves to the address this process uses for it"); + } + { + // A data symbol in the shared cache. + void* expected = dlsym(RTLD_DEFAULT, "environ"); + if (!expected) + skipSuite("Symbol environ", "this system does not export environ"); + else { + Address found = snapshot.symbol("environ"); + TEST_ASSERT(found, "a data symbol in the shared cache is found"); + TEST_ASSERT_HEX_EQ(found.stripped().toMachVMAddress(), + Address(expected).stripped().toMachVMAddress(), + "environ resolves to the address this process uses for it"); + } + } + { + TEST_ASSERT(!snapshot.symbol("jscToolsTestNoSuchSymbolAnywhere"), + "a name that is not exported anywhere is not found"); + TEST_ASSERT(!snapshot.symbol(nullptr), "no name resolves to nothing"); + TEST_ASSERT(!snapshot.symbol(""), "an empty name resolves to nothing"); + } + { + // Only exported symbols appear in a trie. This one is in the binary, and + // still must not be found: saying so is the honest answer. + TEST_ASSERT(jscToolsTestHiddenGlobal == 42, "the hidden global is in this binary"); + TEST_ASSERT(!snapshot.symbol("jscToolsTestHiddenGlobal"), + "a symbol hidden from the linker is not found"); + } + { + // A look up prepends the underscore that a Mach-O symbol name carries, so a + // name that already has one is asking for a different symbol. + TEST_ASSERT(!snapshot.symbol("_malloc"), + "a name given with its underscore already attached is not found"); + } + { + // Resolving is expensive, so a snapshot keeps what it has resolved. + Address first = snapshot.symbol("g_config"); + Address second = snapshot.symbol("g_config"); + TEST_ASSERT(first == second, "resolving the same name twice gives the same address"); + } + { + Symbol symbol(snapshot, "g_config"); + TEST_ASSERT(symbol.name() == "g_config", "a Symbol keeps the name it was asked for"); + TEST_ASSERT(symbol.isValid(), "a Symbol that resolved is valid"); + TEST_ASSERT(symbol.address() == snapshot.symbol("g_config"), + "a Symbol resolves to what the snapshot reports"); + + Symbol missing(snapshot, "jscToolsTestNoSuchSymbolAnywhere"); + TEST_ASSERT(!missing.isValid(), "a Symbol that did not resolve is not valid"); + TEST_ASSERT(!missing.address(), "a Symbol that did not resolve has no address"); + TEST_ASSERT(missing.name() == "jscToolsTestNoSuchSymbolAnywhere", + "a Symbol that did not resolve still knows its name"); + + Symbol unnamed(snapshot, nullptr); + TEST_ASSERT(unnamed.name().empty(), "a Symbol with no name has an empty name"); + TEST_ASSERT(!unnamed.isValid(), "a Symbol with no name is not valid"); + } + { + // A name that is nowhere walks every image in the corpse, which is the most + // work a look up can be asked to do. It has to stay bounded. + static constexpr double budgetSeconds = 60; + MonotonicTime start = MonotonicTime::now(); + TEST_ASSERT(!snapshot.symbol("jscToolsTestAnotherNameThatIsNowhere"), + "an absent name is reported absent"); + double elapsed = (MonotonicTime::now() - start).seconds(); + TEST_ASSERT(elapsed < budgetSeconds, "a look up that finds nothing still finishes"); + if (elapsed >= budgetSeconds) + dataLogLn(" the search took ", elapsed, " seconds"); + } +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.h b/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.h new file mode 100644 index 000000000000..e66d0a11c6a6 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseSymbolTest.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +void testSymbol(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.cpp b/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.cpp new file mode 100644 index 000000000000..5766b8a4a58f --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CorpseThreadTest.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include + +namespace JSCToolsTest { + +using JSC::Corpse::Thread; + +void testThreads() +{ + if (!beginSuite("Thread")) + return; + + static constexpr const char* alphaName = "jsctools alpha"; + static constexpr const char* betaName = "jsctools beta"; + // Longer than a pthread name can hold, so that truncation is exercised. + static constexpr const char* longName = + "jsctools a thread whose name is far too long to fit in the space a pthread name has"; + + ParkedThreads parked; + TEST_ASSERT(parked.spawn(alphaName), "a named thread starts"); + TEST_ASSERT(parked.spawn(betaName), "a second named thread starts"); + TEST_ASSERT(parked.spawn(longName), "a thread with an overlong name starts"); + if (!parked.waitUntilAllParked()) { + TEST_ASSERT(false, "the spawned threads parked themselves"); + return; + } + + SelfSnapshot self; + if (!self.isValid()) + return; + + const Vector& threads = self.snapshot().threads(); + TEST_ASSERT(threads.size() >= 1 + parked.count(), + "the corpse holds at least this process's own threads"); + + bool foundAlpha = false; + bool foundBeta = false; + bool foundTruncated = false; + std::string expectedTruncated(std::string_view(longName).substr(0, ParkedThreads::maximumNameLength)); + + for (const Thread& thread : threads) { + if (thread.name() == alphaName) + foundAlpha = true; + else if (thread.name() == betaName) + foundBeta = true; + else if (thread.name() == expectedTruncated) + foundTruncated = true; + + TEST_ASSERT(thread.id(), "every thread has an identifier"); + TEST_ASSERT(thread.name().length() <= ParkedThreads::maximumNameLength, + "no thread name is longer than a pthread name can be"); + + // The stack is defined as the region the stack pointer points into, so if + // both were read they have to agree. + if (thread.stackPointer()) { + TEST_ASSERT(thread.hasStack(), "a thread with a stack pointer has a stack region"); + if (thread.hasStack()) { + TEST_ASSERT(thread.stackRegion().contains(thread.stackPointer()), + "a thread's stack pointer lies inside its stack region"); + TEST_ASSERT(thread.stackRegion().pageCount() >= thread.stackRegion().residentPageCount(), + "a stack has at least as many pages as it has resident"); + } + } + + TEST_ASSERT(!std::string_view(thread.runStateDescription()).empty(), + "a thread's run state has a name"); + } + + TEST_ASSERT(foundAlpha, "a named thread appears in the corpse under its name"); + TEST_ASSERT(foundBeta, "a second named thread appears under its name"); + TEST_ASSERT(foundTruncated, "an overlong thread name appears cut to what a pthread name holds"); + + // Reading the threads is the expensive part, so it happens once. + const Vector& again = self.snapshot().threads(); + TEST_ASSERT(&again == &threads, "the threads of a snapshot are read once and kept"); + + parked.stopAndJoin(); +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.h b/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.h new file mode 100644 index 000000000000..8a897ad7551c --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/CorpseThreadTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +namespace JSCToolsTest { + +// Takes a corpse of the running test itself, so that everything the corpse +// reports can be checked against what this process already knows. + +void testThreads(); + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.cpp b/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.cpp new file mode 100644 index 000000000000..ad71dbe0365f --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LibJSCToolsTestUtilities.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JSCToolsTest { + +unsigned assertionsRun = 0; +unsigned assertionsFailed = 0; +unsigned suitesSkipped = 0; +const char* suiteFilter = nullptr; + +bool beginSuite(const char* name) +{ + if (suiteFilter && !std::string_view(name).contains(std::string_view(suiteFilter))) + return false; + dataLogLn("--- ", name); + return true; +} + +void skipSuite(const char* name, const char* why) +{ + ++suitesSkipped; + dataLogLn("SKIP: ", name, ": ", why); +} + +unsigned machPortNameCount() +{ + mach_port_name_array_t names = nullptr; + mach_msg_type_number_t nameCount = 0; + mach_port_type_array_t types = nullptr; + mach_msg_type_number_t typeCount = 0; + auto result = mach_port_names(mach_task_self(), &names, &nameCount, &types, &typeCount); + RELEASE_ASSERT(result == KERN_SUCCESS); + + mach_vm_deallocate(mach_task_self(), reinterpret_cast(names), nameCount * sizeof(mach_port_name_t)); + mach_vm_deallocate(mach_task_self(), reinterpret_cast(types), typeCount * sizeof(mach_port_type_t)); + return nameCount; +} + +unsigned machPortSendRightCount(mach_port_t port) +{ + mach_port_urefs_t refs = 0; + auto result = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs); + if (result == KERN_INVALID_NAME) { + // A name this task does not hold is an answer -- it holds no rights under it -- + // rather than a failure. Hence, has no send right. + return 0; + } + RELEASE_ASSERT(result == KERN_SUCCESS); + return refs; // Can still be 0 (which still means no send right). +} + +SelfSnapshot::SelfSnapshot() +{ + m_process = JSC::Corpse::Process::create(getpid()); + if (!m_process->attach()) { + TEST_ASSERT(false, "attaching to this process succeeds"); + return; + } + m_snapshot = WTF::makeUnique(m_process); + if (!m_snapshot->isValid()) + TEST_ASSERT(false, "a snapshot of this process is valid"); +} + +SelfSnapshot::~SelfSnapshot() = default; + +bool SelfSnapshot::isValid() const +{ + return m_snapshot && m_snapshot->isValid(); +} + +JSC::Corpse::Snapshot& SelfSnapshot::snapshot() const +{ + return *m_snapshot; +} + +RefPtr SelfSnapshot::process() const +{ + return m_process; +} + +// One control block for all parked threads, so that they can be told to stop +// together. Only one ParkedThreads is expected to be alive at a time. +static pthread_mutex_t parkMutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned parkedCount = 0; +static bool parkStopping = false; + +struct ParkedThreads::Thread { + pthread_t handle { }; + std::string name; +}; + +static void* parkThread(void* argument) +{ + auto* thread = static_cast(argument); + pthread_setname_np(thread->name.c_str()); + + pthread_mutex_lock(&parkMutex); + ++parkedCount; + while (!parkStopping) { + pthread_mutex_unlock(&parkMutex); + usleep(1000); + pthread_mutex_lock(&parkMutex); + } + pthread_mutex_unlock(&parkMutex); + return nullptr; +} + +ParkedThreads::~ParkedThreads() +{ + stopAndJoin(); +} + +bool ParkedThreads::spawn(const char* name) +{ + auto* thread = new Thread; + // pthread cuts a name that does not fit, and so must this copy, so that the + // name asked for here is the name a corpse will report. + thread->name = std::string_view(name).substr(0, maximumNameLength); + if (pthread_create(&thread->handle, nullptr, parkThread, thread)) { + delete thread; + return false; + } + m_threads.append(thread); + return true; +} + +bool ParkedThreads::waitUntilAllParked() +{ + // Bounded so that a thread that never starts fails the test rather than + // hanging it. + for (unsigned attempt = 0; attempt < 5000; ++attempt) { + pthread_mutex_lock(&parkMutex); + bool ready = parkedCount >= m_threads.size(); + pthread_mutex_unlock(&parkMutex); + if (ready) { + // A thread counts itself as parked just before it settles into its + // wait, so give it that moment before anything reads its state. + usleep(50 * 1000); + return true; + } + usleep(1000); + } + return false; +} + +void ParkedThreads::stopAndJoin() +{ + if (m_threads.isEmpty()) + return; + + pthread_mutex_lock(&parkMutex); + parkStopping = true; + pthread_mutex_unlock(&parkMutex); + + for (Thread* thread : m_threads) { + pthread_join(thread->handle, nullptr); + delete thread; + } + m_threads.clear(); + + pthread_mutex_lock(&parkMutex); + parkStopping = false; + parkedCount = 0; + pthread_mutex_unlock(&parkMutex); +} + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.h b/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.h new file mode 100644 index 000000000000..e34a9abc3c32 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/LibJSCToolsTestUtilities.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JSC { +namespace Corpse { +class Process; +class Snapshot; +} +} + +namespace JSCToolsTest { + +// Assertions report against these, and main reports the totals. +extern unsigned assertionsRun; +extern unsigned assertionsFailed; +extern unsigned suitesSkipped; + +// Only suites whose name contains this substring run. Null runs all of them. +extern const char* suiteFilter; + +bool beginSuite(const char* name); +void skipSuite(const char* name, const char* why); + +// Nothing is printed for a passing assertion: a passing run should be quiet, and +// a failing one should say only what failed. +#define TEST_ASSERT(condition, message) \ + do { \ + ++JSCToolsTest::assertionsRun; \ + if (!(condition)) { \ + ++JSCToolsTest::assertionsFailed; \ + dataLogLn("FAIL: ", message, " (", #condition, ") at ", __FILE__, ":", __LINE__); \ + } \ + } while (0) + +// For values dataLog can print. Reports both sides, which is what makes a +// failure diagnosable without a debugger. +#define TEST_ASSERT_EQ(actual, expected, message) \ + do { \ + ++JSCToolsTest::assertionsRun; \ + auto testActual = (actual); \ + auto testExpected = (expected); \ + if (!(testActual == testExpected)) { \ + ++JSCToolsTest::assertionsFailed; \ + dataLogLn("FAIL: ", message, ": got ", testActual, ", expected ", testExpected, \ + " at ", __FILE__, ":", __LINE__); \ + } \ + } while (0) + +#define TEST_ASSERT_HEX_EQ(actual, expected, message) \ + do { \ + ++JSCToolsTest::assertionsRun; \ + uint64_t testActual = (actual); \ + uint64_t testExpected = (expected); \ + if (testActual != testExpected) { \ + ++JSCToolsTest::assertionsFailed; \ + dataLogLn("FAIL: ", message, ": got 0x", hex(testActual), ", expected 0x", hex(testExpected), \ + " at ", __FILE__, ":", __LINE__); \ + } \ + } while (0) + +// The number of names in this task's Mach port name space. Used to show that a +// sequence of operations leaves no port behind. +unsigned machPortNameCount(); + +// The number of send rights this task holds for `port`, or 0 if it holds no name for +// it. A task that acquires a port it already has a name for gets another reference +// under that same name rather than a new name, so a right that is taken and never +// given back shows up here and not in machPortNameCount(). +unsigned machPortSendRightCount(mach_port_t); + +// Attaches to this process and takes a corpse of it. That is what lets a test +// check what a corpse reports against what this process already knows about +// itself, and it needs no privilege: a task may always snapshot itself. +// +// Reports the failure if either step does not work, so a caller only has to +// check isValid() and return. +class SelfSnapshot { +public: + SelfSnapshot(); + ~SelfSnapshot(); + + SelfSnapshot(const SelfSnapshot&) = delete; + SelfSnapshot& operator=(const SelfSnapshot&) = delete; + + bool isValid() const; + JSC::Corpse::Snapshot& snapshot() const; + RefPtr process() const; + +private: + RefPtr m_process; + std::unique_ptr m_snapshot; +}; + +// Threads that park themselves until stopped, each under a name of our choosing, +// so that a corpse of this process contains threads whose properties are known. +class ParkedThreads { +public: + struct Thread; + + // pthread keeps a thread name in a fixed buffer, so a longer name arrives cut + // to this length. + static constexpr size_t maximumNameLength = 63; + + ~ParkedThreads(); + + // Returns false if the thread could not be created. + bool spawn(const char* name); + + // Blocks until every spawned thread is parked, so that a snapshot taken + // afterwards sees them with their names set and their stacks in use. + bool waitUntilAllParked(); + + void stopAndJoin(); + + size_t count() const { return m_threads.size(); } + +private: + Vector m_threads; +}; + +} // namespace JSCToolsTest + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/corpse/tests/testLibJSCTools.cpp b/Source/JavaScriptCore/corpse/tests/testLibJSCTools.cpp new file mode 100644 index 000000000000..d6da8fecd368 --- /dev/null +++ b/Source/JavaScriptCore/corpse/tests/testLibJSCTools.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include "CorpseAddressTest.h" +#include "CorpseByteParserTest.h" +#include "CorpseExportsTrieTest.h" +#include "CorpseProcessTest.h" +#include "CorpseRegionTest.h" +#include "CorpseSnapshotTest.h" +#include "CorpseSymbolTest.h" +#include "CorpseThreadTest.h" +#include "LibJSCToolsTestUtilities.h" + +#include +#include +#include +#include +#include +#include + +namespace { + +// A default that runs in well under a second, so that every run exercises the +// decoder on inputs nobody wrote. A longer hunt is a matter of passing a bigger +// count and a different seed. +constexpr uint64_t defaultFuzzSeed = 0x5eed1234; +constexpr unsigned defaultFuzzIterations = 20000; + +void printUsage() +{ + dataLogLn("Usage: testLibJSCTools []"); + dataLogLn(" testLibJSCTools --fuzz-trie [ []]"); + dataLogLn(""); + dataLogLn(" Runs the tests for libJavaScriptCoreTools. With a filter, only the"); + dataLogLn(" suites whose name contains it run."); +} + +bool parseUint64(std::string_view text, uint64_t& out) +{ + uint8_t base = text.starts_with("0x") || text.starts_with("0X") ? 16 : 10; + if (base == 16) + text = text.substr(2); + auto parsed = WTF::parseInteger(StringView::fromLatin1(std::string(text).c_str()), base); + if (!parsed) + return false; + out = *parsed; + return true; +} + +} // anonymous namespace + +int main(int argc, char** argv) +{ + uint64_t fuzzSeed = defaultFuzzSeed; + uint64_t fuzzIterations = defaultFuzzIterations; + bool fuzzOnly = false; + + // argv is wrapped in a span so that nothing here walks off the end of it. + auto arguments = unsafeMakeSpan(argv, static_cast(argc)); + for (size_t index = 1; index < arguments.size(); ++index) { + std::string_view argument = arguments[index]; + if (argument == "--help" || argument == "-h") { + printUsage(); + return 0; + } + if (argument == "--fuzz-trie") { + fuzzOnly = true; + if (index + 1 < arguments.size() && parseUint64(arguments[index + 1], fuzzSeed)) { + ++index; + if (index + 1 < arguments.size() && parseUint64(arguments[index + 1], fuzzIterations)) + ++index; + } + continue; + } + if (argument.starts_with("-")) { + dataLogLn("Unknown option '", arguments[index], "'"); + printUsage(); + return 1; + } + JSCToolsTest::suiteFilter = arguments[index]; + } + + dataLogLn("Starting libJavaScriptCoreTools tests"); + + if (fuzzOnly) + JSCToolsTest::fuzzExportsTrie(fuzzSeed, static_cast(fuzzIterations)); + else { + JSCToolsTest::testByteParser(); + JSCToolsTest::testExportsTrie(); + JSCToolsTest::fuzzExportsTrie(fuzzSeed, static_cast(fuzzIterations)); + JSCToolsTest::testAddress(); + JSCToolsTest::testProcess(); + JSCToolsTest::testSnapshot(); + JSCToolsTest::testRegion(); + JSCToolsTest::testThreads(); + JSCToolsTest::testSymbol(); + } + + dataLogLn("Ran ", JSCToolsTest::assertionsRun, " assertions, ", + JSCToolsTest::assertionsFailed, " failed, ", + JSCToolsTest::suitesSkipped, " suites skipped"); + + if (JSCToolsTest::assertionsFailed) { + dataLogLn("Some libJavaScriptCoreTools tests FAILED!"); + return 1; + } + if (!JSCToolsTest::assertionsRun) { + dataLogLn("No tests ran!"); + return 1; + } + + dataLogLn("All libJavaScriptCoreTools tests PASSED!"); + return 0; +} + +#else // libJavaScriptCoreTools support unavailable + +int main(int, char**) +{ + // The corpse support is built on Mach task APIs, so there is nothing to test + // on other platforms. Simulators and MacCatalyst are also not supported. + // Report success so that a run here is not a failure. + printf("Not supported platform for testLibJSCTools\n"); + return 0; +} + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp index b90a0b9649cf..52567cea948e 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp @@ -33,6 +33,7 @@ #include "DFGArgumentsUtilities.h" #include #include "DFGClobberize.h" +#include "DFGCombinedLiveness.h" #include "DFGForAllKills.h" #include "DFGGraph.h" #include "DFGInsertionSet.h" @@ -722,7 +723,16 @@ class ArgumentsEliminationPhase : public Phase { } if (clobberStack) { - for (Node* node : combinedLiveness.liveAtTail[block]) + // liveAtTail is the union of the CFG successors' liveAtHead, but a candidate can be kept + // alive solely by an exceptional exit to a catch entrypoint, which the DFG models as a + // non-CFG successor. Such a candidate is OSR-live at the terminal yet absent from + // liveAtTail, so a clobber of its source slots in this block would otherwise go + // unnoticed. Cover that gap with the nodes live at the terminal but dead on the tail. + // FIXME: If this is ever too conservative we can just calculate the locals used by + // the catch block for the terminal. + NodeSet possiblyLiveOut = bytecodeLivenessAtTerminal(m_graph, block); + possiblyLiveOut.addAll(combinedLiveness.liveAtTail[block]); + for (Node* node : possiblyLiveOut) removeViaKill(block, block->size(), node); for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp index 3d34454eac5b..0601017db462 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -36,10 +36,10 @@ namespace JSC { namespace DFG { -ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe) +ArrayMode ArrayMode::fromObserved(ArrayProfile profile, Array::Action action, bool makeSafe) { Array::Class nonArray; - if (profile->usesOriginalArrayStructures(locker)) + if (profile.usesOriginalArrayStructures()) nonArray = Array::OriginalNonArray; else nonArray = Array::NonArray; @@ -63,27 +63,27 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile else converts = Array::AsIs; - return ArrayMode(type, isArray, converts, action).withProfile(locker, profile, makeSafe); + return ArrayMode(type, isArray, converts, action).withProfile(profile, makeSafe); }; - ArrayModes observed = profile->observedArrayModes(locker); + ArrayModes observed = profile.observedArrayModes(); switch (observed) { case 0: return ArrayMode(Array::Unprofiled); case asArrayModesIgnoringTypedArrays(NonArray): - if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) + if (action == Array::Write && !profile.mayInterceptIndexedAccesses()) return ArrayMode(Array::SelectUsingArguments, nonArray, Array::OutOfBounds, Array::Convert, action); - return ArrayMode(Array::SelectUsingPredictions, nonArray, action).withSpeculationFromProfile(locker, profile, makeSafe); + return ArrayMode(Array::SelectUsingPredictions, nonArray, action).withSpeculationFromProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(ArrayWithUndecided): if (action == Array::Write) return ArrayMode(Array::SelectUsingArguments, Array::Array, Array::OutOfBounds, Array::Convert, action); - return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(NonArray) | asArrayModesIgnoringTypedArrays(ArrayWithUndecided): - if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) + if (action == Array::Write && !profile.mayInterceptIndexedAccesses()) return ArrayMode(Array::SelectUsingArguments, Array::PossiblyArray, Array::OutOfBounds, Array::Convert, action); - return ArrayMode(Array::SelectUsingPredictions, action).withSpeculationFromProfile(locker, profile, makeSafe); + return ArrayMode(Array::SelectUsingPredictions, action).withSpeculationFromProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(NonArrayWithInt32): case asArrayModesIgnoringTypedArrays(ArrayWithInt32): @@ -113,52 +113,52 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile return handleContiguousModes(Array::Contiguous, observed); case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage): case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage): - return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage): case asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage): - return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage): - return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(profile, makeSafe); case asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage): case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage): - return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(profile, makeSafe); case Int8ArrayMode: - return ArrayMode(Array::Int8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Int8Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Int16ArrayMode: - return ArrayMode(Array::Int16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Int16Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Int32ArrayMode: - return ArrayMode(Array::Int32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Int32Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Uint8ArrayMode: - return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Uint8ClampedArrayMode: - return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Uint16ArrayMode: - return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Uint32ArrayMode: - return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Float16ArrayMode: - return ArrayMode(Array::Float16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Float16Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Float32ArrayMode: - return ArrayMode(Array::Float32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Float32Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case Float64ArrayMode: - return ArrayMode(Array::Float64Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Float64Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case BigInt64ArrayMode: - return ArrayMode(Array::BigInt64Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::BigInt64Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); case BigUint64ArrayMode: - return ArrayMode(Array::BigUint64Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::BigUint64Array, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); default: // If we have seen multiple TypedArray types, or a TypedArray and non-typed array, it doesn't make sense to try to convert the object since you can't convert typed arrays. if (observed & ALL_TYPED_ARRAY_MODES) - return ArrayMode(Array::Generic, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); + return ArrayMode(Array::Generic, nonArray, Array::AsIs, action).withProfile(profile, makeSafe); - if ((observed & asArrayModesIgnoringTypedArrays(NonArray)) && profile->mayInterceptIndexedAccesses(locker)) - return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe); + if ((observed & asArrayModesIgnoringTypedArrays(NonArray)) && profile.mayInterceptIndexedAccesses()) + return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(profile, makeSafe); Array::Type type; Array::Class arrayClass; @@ -185,7 +185,7 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile else arrayClass = Array::PossiblyArray; - return ArrayMode(type, arrayClass, Array::Convert, action).withProfile(locker, profile, makeSafe); + return ArrayMode(type, arrayClass, Array::Convert, action).withProfile(profile, makeSafe); } } diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h index 45f4d92ce9f5..051e6ad0f2a3 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.h +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h @@ -209,7 +209,7 @@ class ArrayMode { return ArrayMode(word); } - static ArrayMode fromObserved(const ConcurrentJSLocker&, ArrayProfile*, Array::Action, bool makeSafe); + static ArrayMode fromObserved(ArrayProfile, Array::Action, bool makeSafe); ArrayMode withType(Array::Type type) const { @@ -246,31 +246,31 @@ class ArrayMode { return ArrayMode(type(), arrayClass, speculation(), conversion(), action(), mayBeLargeTypedArray(), mayBeResizableOrGrowableSharedTypedArray()); } - static Array::Speculation speculationFromProfile(const ConcurrentJSLocker& locker, ArrayProfile* profile, bool makeSafe) + static Array::Speculation speculationFromProfile(ArrayProfile profile, bool makeSafe) { if (makeSafe) return Array::OutOfBounds; - else if (profile->mayStoreToHole(locker)) + else if (profile.mayStoreToHole()) return Array::ToHole; else return Array::InBounds; } - ArrayMode withSpeculationFromProfile(const ConcurrentJSLocker& locker, ArrayProfile* profile, bool makeSafe) const + ArrayMode withSpeculationFromProfile(ArrayProfile profile, bool makeSafe) const { - return withSpeculation(speculationFromProfile(locker, profile, makeSafe)); + return withSpeculation(speculationFromProfile(profile, makeSafe)); } - ArrayMode withProfile(const ConcurrentJSLocker& locker, ArrayProfile* profile, bool makeSafe) const + ArrayMode withProfile(ArrayProfile profile, bool makeSafe) const { Array::Class myArrayClass; if (isJSArray()) { - if (profile->usesOriginalArrayStructures(locker) && benefitsFromOriginalArray()) { + if (profile.usesOriginalArrayStructures() && benefitsFromOriginalArray()) { switch (type()) { case Array::Int32: case Array::Double: case Array::Contiguous: { - ArrayModes arrayModes = profile->observedArrayModes(locker); + ArrayModes arrayModes = profile.observedArrayModes(); if (hasSeenCopyOnWriteArray(arrayModes) && !hasSeenWritableArray(arrayModes)) myArrayClass = Array::OriginalCopyOnWriteArray; else if (!hasSeenCopyOnWriteArray(arrayModes) && hasSeenWritableArray(arrayModes)) @@ -293,11 +293,9 @@ class ArrayMode { } else myArrayClass = arrayClass(); - Array::Speculation speculation = speculationFromProfile(locker, profile, makeSafe); + Array::Speculation speculation = speculationFromProfile(profile, makeSafe); - bool mayBeLargeTypedArray = profile->mayBeLargeTypedArray(locker); - bool mayBeResizableOrGrowableSharedTypedArray = profile->mayBeResizableOrGrowableSharedTypedArray(locker); - return withArrayClassAndSpeculation(myArrayClass, speculation, mayBeLargeTypedArray, mayBeResizableOrGrowableSharedTypedArray); + return withArrayClassAndSpeculation(myArrayClass, speculation, profile.mayBeLargeTypedArray(), profile.mayBeResizableOrGrowableSharedTypedArray()); } static constexpr SpeculatedType unusedIndexSpeculatedType = SpecInt32Only; diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 983da967562c..7d149beffad8 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -1346,34 +1346,26 @@ class ByteCodeParser { ArrayMode getArrayMode(Array::Action action) { CodeBlock* codeBlock = m_inlineStackTop->m_profiledBlock; - ConcurrentJSLocker locker(codeBlock->m_lock); - ArrayProfile* profile = codeBlock->getArrayProfile(locker, codeBlock->bytecodeIndex(m_currentInstruction)); + ArrayProfile* profile = codeBlock->getArrayProfile(codeBlock->bytecodeIndex(m_currentInstruction)); if (!profile) return { }; - return getArrayMode(locker, *profile, action); + return getArrayMode(*profile, action); } - ArrayMode getArrayMode(ArrayProfile& profile, Array::Action action) + ArrayMode getArrayMode(ArrayProfile& liveProfile, Array::Action action) { - ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); - return getArrayMode(locker, profile, action); - } - - ArrayMode getArrayMode(const ConcurrentJSLocker& locker, ArrayProfile& profile, Array::Action action) - { - profile.computeUpdatedPrediction(m_inlineStackTop->m_profiledBlock); - bool makeSafe = profile.outOfBounds(locker); - return ArrayMode::fromObserved(locker, &profile, action, makeSafe); + liveProfile.computeUpdatedPrediction(m_inlineStackTop->m_profiledBlock); + ArrayProfile profile = liveProfile; + return ArrayMode::fromObserved(profile, action, profile.outOfBounds()); } bool profiledArrayMayBeRegExpMatchesArray() { CodeBlock* codeBlock = m_inlineStackTop->m_profiledBlock; - ConcurrentJSLocker locker(codeBlock->m_lock); - ArrayProfile* profile = codeBlock->getArrayProfile(locker, codeBlock->bytecodeIndex(m_currentInstruction)); + ArrayProfile* profile = codeBlock->getArrayProfile(codeBlock->bytecodeIndex(m_currentInstruction)); if (!profile) return false; - return profile->mayBeRegExpMatchesArray(locker); + return profile->mayBeRegExpMatchesArray(); } Node* makeSafe(Node* node) diff --git a/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp index b8cd7406d5aa..116bd7e9004f 100644 --- a/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp +++ b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp @@ -61,6 +61,13 @@ NodeSet liveNodesAtHead(Graph& graph, BasicBlock* block) return seen; } +NodeSet bytecodeLivenessAtTerminal(Graph& graph, BasicBlock* block) +{ + NodeSet seen; + addBytecodeLiveness(graph, block->ssa->availabilityAtTail, seen, block->last()); + return seen; +} + CombinedLiveness::CombinedLiveness(Graph& graph) : liveAtHead(graph.numBlocks()) , liveAtTail(graph.numBlocks()) @@ -80,11 +87,8 @@ CombinedLiveness::CombinedLiveness(Graph& graph) // Unreachable // // And things may definitely be live in bytecode at that point in the program. - if (!block->numSuccessors()) { - NodeSet seen; - addBytecodeLiveness(graph, block->ssa->availabilityAtTail, seen, block->last()); - liveAtTail[block] = seen; - } + if (!block->numSuccessors()) + liveAtTail[block] = bytecodeLivenessAtTerminal(graph, block); } // Now compute the liveAtTail by unifying the liveAtHead of the successors. diff --git a/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h index a31846febbb4..4d16de38db1f 100644 --- a/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h +++ b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h @@ -35,6 +35,8 @@ namespace JSC { namespace DFG { // Returns the set of nodes live at head, both due to DFG and due to bytecode (i.e. OSR exit). NodeSet liveNodesAtHead(Graph&, BasicBlock*); +NodeSet bytecodeLivenessAtTerminal(Graph&, BasicBlock*); + // WARNING: This currently does not reason about the liveness of shadow values. The execution // semantics of DFG SSA are that an Upsilon stores to the shadow value of a Phi, and the Phi loads // from that shadow value. Hence, the shadow values are like variables, and have liveness. The normal diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index 9f2e887d0cd9..c71dd9571197 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -1373,9 +1373,8 @@ class FixupPhase : public Phase { ArrayModes arrayModes = 0; { CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic); - ConcurrentJSLocker locker(profiledBlock->m_lock); - if (ArrayProfile* arrayProfile = profiledBlock->getArrayProfile(locker, node->origin.semantic.bytecodeIndex())) - arrayModes = arrayProfile->observedArrayModes(locker); + if (ArrayProfile* arrayProfile = profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex())) + arrayModes = arrayProfile->observedArrayModes(); } auto info = refineArrayModesForMultiGetByVal(node, arrayModes); if (!info) @@ -1564,9 +1563,8 @@ class FixupPhase : public Phase { ArrayModes arrayModes = 0; { CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic); - ConcurrentJSLocker locker(profiledBlock->m_lock); - if (ArrayProfile* arrayProfile = profiledBlock->getArrayProfile(locker, node->origin.semantic.bytecodeIndex())) - arrayModes = arrayProfile->observedArrayModes(locker); + if (ArrayProfile* arrayProfile = profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex())) + arrayModes = arrayProfile->observedArrayModes(); } if (auto result = refineArrayModesForMultiPutByVal(node, arrayModes)) { if (m_graph.hasExitSite(node->origin.semantic, OutOfBounds)) { @@ -5261,11 +5259,10 @@ class FixupPhase : public Phase { ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions, Array::Read); { CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic); - ConcurrentJSLocker locker(profiledBlock->m_lock); - ArrayProfile* arrayProfile = profiledBlock->getArrayProfile(locker, node->origin.semantic.bytecodeIndex()); - if (arrayProfile) { - arrayProfile->computeUpdatedPrediction(profiledBlock); - arrayMode = ArrayMode::fromObserved(locker, arrayProfile, Array::Read, false); + ArrayProfile* liveProfile = profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex()); + if (liveProfile) { + liveProfile->computeUpdatedPrediction(profiledBlock); + arrayMode = ArrayMode::fromObserved(*liveProfile, Array::Read, false); if (arrayMode.type() == Array::Unprofiled) { // For normal array operations, it makes sense to treat Unprofiled // accesses as ForceExit and get more data rather than using diff --git a/Source/JavaScriptCore/dfg/DFGForAllKills.h b/Source/JavaScriptCore/dfg/DFGForAllKills.h index 6cc22cb83256..8b1a134070b6 100644 --- a/Source/JavaScriptCore/dfg/DFGForAllKills.h +++ b/Source/JavaScriptCore/dfg/DFGForAllKills.h @@ -34,10 +34,6 @@ namespace JSC { namespace DFG { -namespace ForAllKillsInternal { -constexpr bool verbose = false; -} - // Utilities for finding the last points where a node is live in DFG SSA. This accounts for liveness due // to OSR exit. This is usually used for enumerating over all of the program points where a node is live, // by exploring all blocks where the node is live at tail and then exploring all program points where the @@ -170,34 +166,6 @@ void forAllKilledNodesAtNodeIndex( }); } -// Tells you all of the places to start searching from in a basic block. Gives you the node index at which -// the value is either no longer live. This pretends that nodes are dead at the end of the block, so that -// you can use this to do per-basic-block analyses. -template Functor> -void forAllKillsInBlock( - Graph& graph, const CombinedLiveness& combinedLiveness, BasicBlock* block, - const Functor& functor) -{ - for (Node* node : combinedLiveness.liveAtTail[block]) - functor(block->size(), node); - - LocalOSRAvailabilityCalculator localAvailability(graph); - localAvailability.beginBlock(block); - // Start running functor at the second node, because the functor is expected to only inspect nodes from the start of - // the block up to nodeIndex (exclusive), so if nodeIndex is zero then the functor has nothing to do. - for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { - dataLogLnIf(ForAllKillsInternal::verbose, "local availability at index: ", nodeIndex, " ", localAvailability.m_availability); - if (nodeIndex) { - forAllKilledNodesAtNodeIndex( - graph, localAvailability.m_availability, block, nodeIndex, - [&] (Node* node) { - functor(nodeIndex, node); - }); - } - localAvailability.executeNode(block->at(nodeIndex)); - } -} - } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp index 690d784b2fac..8f25e4e705c8 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp @@ -359,8 +359,10 @@ void LocalOSRAvailabilityCalculator::executeNode(Node* node) case LoadVarargs: case ForwardVarargs: { LoadVarargsData* data = node->loadVarargsData(); + killHeaps(data->count); m_availability.m_locals.operand(data->count) = Availability(node->child1().node(), FlushedAt(FlushedInt32, data->machineCount)); for (unsigned i = data->limit; i--;) { + killHeaps(data->start + i); m_availability.m_locals.operand(data->start + i) = Availability(FlushedAt(FlushedJSValue, data->machineStart.isValid() ? (data->machineStart + i) : VirtualRegister())); } diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp index 67c56dae3717..a637b93e2114 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp @@ -325,7 +325,7 @@ void OSRExit::compileExit(CCallHelpers& jit, VM& vm, const OSRExit& exit, const CodeOrigin codeOrigin = exit.m_codeOriginForExitProfile; CodeBlock* codeBlock = jit.baselineCodeBlockFor(codeOrigin); - if (ArrayProfile* arrayProfile = codeBlock->getArrayProfile(ConcurrentJSLocker(codeBlock->m_lock), codeOrigin.bytecodeIndex())) { + if (ArrayProfile* arrayProfile = codeBlock->getArrayProfile(codeOrigin.bytecodeIndex())) { GPRReg usedRegister; if (exit.m_jsValueSource.isAddress()) usedRegister = exit.m_jsValueSource.base(); diff --git a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp index 78a6333a0270..0324ff8c29d1 100644 --- a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp @@ -264,7 +264,7 @@ static void compileStub(VM& vm, unsigned exitID, JITCode* jitCode, OSRExit& exit if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) { CodeOrigin codeOrigin = exit.m_codeOriginForExitProfile; CodeBlock* codeBlock = jit.baselineCodeBlockFor(codeOrigin); - if (ArrayProfile* arrayProfile = codeBlock->getArrayProfile(ConcurrentJSLocker(codeBlock->m_lock), codeOrigin.bytecodeIndex())) { + if (ArrayProfile* arrayProfile = codeBlock->getArrayProfile(codeOrigin.bytecodeIndex())) { jit.move(CCallHelpers::TrustedImmPtr(arrayProfile), GPRInfo::regT3); jit.load32(MacroAssembler::Address(GPRInfo::regT0, JSCell::structureIDOffset()), GPRInfo::regT1); jit.store32(GPRInfo::regT1, CCallHelpers::Address(GPRInfo::regT3, ArrayProfile::offsetOfSpeculationFailureStructureID())); diff --git a/Source/JavaScriptCore/inspector/agents/InspectorAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorAgent.cpp index 1343b440d37c..d4ba877730f3 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorAgent.cpp @@ -43,7 +43,7 @@ InspectorAgent::InspectorAgent(AgentContext& context) : InspectorAgentBase("Inspector"_s) , m_environment(context.environment) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(InspectorBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(InspectorBackendDispatcher::create(protect(context.backendDispatcher), this)) { } diff --git a/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.cpp index 9c0943e7c1b0..693d154dab51 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.cpp @@ -44,7 +44,7 @@ WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorAuditAgent); InspectorAuditAgent::InspectorAuditAgent(AgentContext& context) : InspectorAgentBase("Audit"_s) - , m_backendDispatcher(AuditBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(AuditBackendDispatcher::create(protect(context.backendDispatcher), this)) , m_injectedScriptManager(context.injectedScriptManager) , m_debugger(CheckedRef { context.environment }->debugger()) { diff --git a/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp index 074cd02f2eb6..2398ddf05320 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp @@ -46,7 +46,7 @@ InspectorConsoleAgent::InspectorConsoleAgent(AgentContext& context) : InspectorAgentBase("Console"_s) , m_injectedScriptManager(context.injectedScriptManager) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(ConsoleBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(ConsoleBackendDispatcher::create(protect(context.backendDispatcher), this)) { } diff --git a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp index 532b83432c39..3b82f9acd297 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp @@ -269,7 +269,7 @@ RefPtr InspectorDebuggerAgent::debuggerBreakpointFromPayload(Pr InspectorDebuggerAgent::InspectorDebuggerAgent(AgentContext& context) : InspectorAgentBase("Debugger"_s) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(DebuggerBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(DebuggerBackendDispatcher::create(protect(context.backendDispatcher), this)) , m_debugger(*CheckedRef { context.environment }->debugger()) , m_injectedScriptManager(context.injectedScriptManager) { diff --git a/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp index 90d674e4dbad..92363e58b04c 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp @@ -48,7 +48,7 @@ InspectorHeapAgent::InspectorHeapAgent(AgentContext& context) : InspectorAgentBase("Heap"_s) , m_injectedScriptManager(context.injectedScriptManager) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(HeapBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(HeapBackendDispatcher::create(protect(context.backendDispatcher), this)) , m_environment(context.environment) { } diff --git a/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp index 430a0f5ed8f1..2b4df03ddc43 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp @@ -43,7 +43,7 @@ WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorScriptProfilerAgent); InspectorScriptProfilerAgent::InspectorScriptProfilerAgent(AgentContext& context) : InspectorAgentBase("ScriptProfiler"_s) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(ScriptProfilerBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(ScriptProfilerBackendDispatcher::create(protect(context.backendDispatcher), this)) , m_environment(context.environment) { } diff --git a/Source/JavaScriptCore/inspector/agents/JSGlobalObjectRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/JSGlobalObjectRuntimeAgent.cpp index b43bf2c0a905..801bfccddc56 100644 --- a/Source/JavaScriptCore/inspector/agents/JSGlobalObjectRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/JSGlobalObjectRuntimeAgent.cpp @@ -40,7 +40,7 @@ WTF_MAKE_TZONE_ALLOCATED_IMPL(JSGlobalObjectRuntimeAgent); JSGlobalObjectRuntimeAgent::JSGlobalObjectRuntimeAgent(JSAgentContext& context) : InspectorRuntimeAgent(context) , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) - , m_backendDispatcher(RuntimeBackendDispatcher::create(context.backendDispatcher, this)) + , m_backendDispatcher(RuntimeBackendDispatcher::create(protect(context.backendDispatcher), this)) , m_globalObject(context.inspectedGlobalObject) { } diff --git a/Source/JavaScriptCore/inspector/remote/cocoa/RemoteInspectorCocoa.mm b/Source/JavaScriptCore/inspector/remote/cocoa/RemoteInspectorCocoa.mm index 404bc4fad14d..469033e6b96b 100644 --- a/Source/JavaScriptCore/inspector/remote/cocoa/RemoteInspectorCocoa.mm +++ b/Source/JavaScriptCore/inspector/remote/cocoa/RemoteInspectorCocoa.mm @@ -127,7 +127,7 @@ static bool canAccessWebInspectorMachPort() } RemoteInspector::RemoteInspector() - : m_xpcQueue(adoptOSObject(dispatch_queue_create("com.apple.JavaScriptCore.remote-inspector-xpc", DISPATCH_QUEUE_SERIAL))) + : m_xpcQueue(adoptOSObject(dispatch_queue_create("com.apple.JavaScriptCore.remote-inspector-xpc", serialQueueWithAutoreleasePoolAttrSingleton()))) { } diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp index ecaae8c39f92..19bd4bce03e5 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -465,7 +465,6 @@ void JIT::emit_op_iterator_next(const JSInstruction* instruction) genericCases.append(branchIfNotType(nextJSR.payloadGPR(), SentinelType)); JumpList doneCases; -#if CPU(ARM64) || CPU(X86_64) loadGlobalObject(argumentGPR0); emitGetVirtualRegister(bytecode.m_iterator, argumentGPR1); emitGetVirtualRegister(bytecode.m_iterable, argumentGPR2); @@ -474,19 +473,7 @@ void JIT::emit_op_iterator_next(const JSInstruction* instruction) emitPutVirtualRegister(bytecode.m_done, returnValueGPR); emitPutVirtualRegister(bytecode.m_value, returnValueGPR2); doneCases.append(branchIfEmpty(JSValueRegs { returnValueGPR2 })); - emitValueProfilingSite(bytecode, JSValueRegs { returnValueGPR2 }); -#else - auto* tryFastFunction = ([&] () { - switch (instruction->width()) { - case Narrow: return iterator_next_try_fast_narrow; - case Wide16: return iterator_next_try_fast_wide16; - case Wide32: return iterator_next_try_fast_wide32; - default: RELEASE_ASSERT_NOT_REACHED(); - } - })(); - JITSlowPathCall slowPathCall(this, tryFastFunction); - slowPathCall.call(); -#endif + emitValueProfilingSite(bytecode, m_bytecodeIndex.withCheckpoint(OpIteratorNext::getValue), JSValueRegs { returnValueGPR2 }); doneCases.append(jump()); genericCases.link(this); diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index cdb26ba465bc..92c287e33ab4 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -129,6 +129,7 @@ #include #include #include +#include #endif #if PLATFORM(GTK) @@ -4941,7 +4942,7 @@ int jscmain(int argc, char** argv) auto& memoryPressureHandler = MemoryPressureHandler::singleton(); { // FIXME: This is a false positive. rdar://160931336 - SUPPRESS_RETAINPTR_CTOR_ADOPT auto queue = adoptOSObject(dispatch_queue_create("jsc shell memory pressure handler", DISPATCH_QUEUE_SERIAL)); + SUPPRESS_RETAINPTR_CTOR_ADOPT OSObjectPtr queue = adoptOSObject(dispatch_queue_create("jsc shell memory pressure handler", serialQueueWithAutoreleasePoolAttrSingleton())); memoryPressureHandler.setDispatchQueue(WTF::move(queue)); } Box memoryPressureCriticalState = Box::create(Critical::No); diff --git a/Source/JavaScriptCore/mya/mya.cpp b/Source/JavaScriptCore/mya/mya.cpp new file mode 100644 index 000000000000..1ee8ccd46547 --- /dev/null +++ b/Source/JavaScriptCore/mya/mya.cpp @@ -0,0 +1,1407 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE(READLINE) +// readline/history.h has a Function typedef that conflicts with WTF::Function; +// rename it across these includes to avoid the clash. +#define Function ReadlineFunction +#include +#include +#undef Function +#endif + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +using JSC::Corpse::Address; +using JSC::Corpse::Process; +using JSC::Corpse::Snapshot; +using JSC::Corpse::Thread; + +namespace Mya { + +// A lexer over a null-terminated string. Parsing methods skip leading +// whitespace and advance past whatever they consume; a failed parse leaves the +// position where it was. A Lexer is essentially made up of a position in the +// string. So copying one is how you look ahead without committing. +class Lexer { +public: + explicit Lexer(const char* text) + : m_at(text) + { + } + + void skipWhitespace() + { + while (isTabOrSpace(*m_at)) + ++m_at; + } + + // True if only whitespace remains. + bool atEnd() + { + skipWhitespace(); + return !*m_at; + } + + // The next non-whitespace character, or '\0' at end of input. + char peek() + { + skipWhitespace(); + return *m_at; + } + + // Consumes and returns the next whitespace-delimited token, which is empty + // at end of input. + std::string_view nextToken() + { + skipWhitespace(); + const char* start = m_at; + while (*m_at && !isTabOrSpace(*m_at)) + ++m_at; + return std::string_view(start, static_cast(m_at - start)); + } + + // Consumes the next token only if it matches word. + bool consumeToken(const char* word) + { + Lexer probe = *this; + if (probe.nextToken() != word) + return false; + *this = probe; + return true; + } + + // Consumes the next non-whitespace character only if it matches c. + bool consumeChar(char c) + { + skipWhitespace(); + if (*m_at != c) + return false; + ++m_at; + return true; + } + + // Consumes a positive number from the specified `minimum` upwards, but capped at INT_MAX. + template + bool consumeUint32(T& out) + { + skipWhitespace(); + if (!isASCIIDigit(*m_at)) + return false; // Rejects cases like -0, -1, +3, which strtol allows. + errno = 0; + char* end = nullptr; + long value = strtol(m_at, &end, 10); + if (end == m_at || errno || value < minimum || value > INT_MAX) + return false; + m_at = end; + out = static_cast(value); + return true; + } + + bool consumePID(pid_t& pid) { return consumeUint32<1>(pid); } + +private: + const char* m_at; +}; + +class Shell { +public: + ~Shell() + { + cleanup(); + } + + int run(int argc, char** argv) + { + JSC::Corpse::Client::setName("mya"_s); + auto action = parseArguments(argc, argv); + switch (action) { + case ContinuationAction::Continue: + openHistory(); + runInteractive(); + return 0; + case ContinuationAction::Exit: + return 0; + case ContinuationAction::Error: + return 1; + } + RELEASE_ASSERT_NOT_REACHED(); + return 1; + } + +private: + static constexpr const char* prompt = ">>> "; + static constexpr const char* historyDirName = ".mya"; + static constexpr const char* historyFileName = "history"; + static constexpr unsigned defaultMaxHistoryEntries = 50; + static constexpr unsigned minHistorySize = 5; + + // The history file records the target max history entries in its first line, followed by + // historical commands. To avoid re-writing the file on every new command, we allow the file + // to exceed the max entries by maxOverflowEntries, before we do a re-write to purge + // the extra entries. We will keep appending to the same file until the re-write is needed. + static constexpr const char* maxEntriesHeaderPrefix = "max entries "; + static constexpr unsigned maxOverflowEntries = 100; + + static void printUsage(FILE* out) + { + fputs("Mya (MY-uh /ˈmaɪə/) - MemorY Analyzer\n", out); + fputs("Usage:\n", out); + fputs(" mya [--pid|-p ]\n", out); + fputs(" mya [--help|-h []]\n", out); + fputs("Commands:\n", out); + fputs(" attach [--pid|-p] Set the target PID and attach\n", out); + fputs(" detach Detach from the current PID\n", out); + fputs(" status (st) Show whether mya is attached\n", out); + fputs(" snapshot (sn, snap) ... Capture and manage snapshots\n", out); + fputs(" thread (th) ... Inspect the threads in a snapshot\n", out); + fputs(" p[/x] & Print a symbol's address, /x for hex\n", out); + fputs(" history (hi, hist) ... Show and manage the command history\n", out); + fputs(" help [] Show this help, or help for \n", out); + fputs(" quit (q, exit) Exit mya\n", out); + fputs("\n", out); + fputs(" Use `help snapshot`, `help thread` or `help history` for their subcommands.\n", out); + fputs("\n", out); + } + + static void printThreadUsage(FILE* out) + { + fputs("thread - inspect the threads captured in a snapshot\n", out); + fputs(" thread list (li) List the threads in the snapshot in use\n", out); + fputs("\n", out); + fputs(" `thread` may be abbreviated as `th`, and lists by default.\n", out); + fputs(" Threads are read from the snapshot in use; see `help snapshot`.\n", out); + fputs("\n", out); + } + + static void printSnapshotUsage(FILE* out) + { + fputs("snapshot - capture and manage snapshots of a process\n", out); + fputs(" snapshot Capture a snapshot of the current process\n", out); + fputs(" snapshot --pid|-p Attach to and capture a snapshot of it\n", out); + fputs(" snapshot Switch to using snapshot \n", out); + fputs(" snapshot list (li) List captured snapshots (* marks the one in use)\n", out); + fputs(" snapshot info (inf) Show details of snapshot \n", out); + fputs(" snapshot delete (del) Delete snapshot \n", out); + fputs(" snapshot diff Diff snapshot against snapshot \n", out); + fputs("\n", out); + fputs(" `snapshot` may be abbreviated as `sn` or `snap`.\n", out); + fputs(" Capturing a snapshot switches to using it.\n", out); + fputs("\n", out); + } + + static void printHistoryUsage(FILE* out) + { + fputs("history - show and manage the command history\n", out); + fputs(" history List the command history\n", out); + fputs(" history clear [] Clear the history, or its oldest entries\n", out); + fputs(" history size [] Show or set the max entries kept\n", out); + fputs(" ! Replay history entry \n", out); + fputs(" !! Replay the previous command\n", out); + fputs("\n", out); + fputs(" `history` may be abbreviated as `hi` or `hist`.\n", out); + fprintf(out, " Command history is kept (defaults up to %u entries) in ~/%s/%s.\n", + defaultMaxHistoryEntries, historyDirName, historyFileName); +#if HAVE(READLINE) + fputs(" It is navigable with the Up/Down arrows and Ctrl-R reverse search.\n", out); +#endif + fputs("\n", out); + } + + // Dispatches `help []`. `lex` is positioned after the "help" word. + static bool handleHelp(Lexer lex) + { + if (lex.atEnd()) { + printUsage(stdout); + return true; + } + std::string_view topic = lex.nextToken(); + if (topic == "sn" || topic == "snap" || topic == "snapshot") { + printSnapshotUsage(stdout); + return true; + } + if (topic == "hi" || topic == "hist" || topic == "history") { + printHistoryUsage(stdout); + return true; + } + if (topic == "th" || topic == "thread") { + printThreadUsage(stdout); + return true; + } + fprintf(stderr, "mya: No help for '%.*s'\n", static_cast(topic.length()), topic.data()); + return false; + } + + // Writes a byte count in the largest unit that keeps it readable, e.g. "512 KB" or "1.50 MB". + static void formatByteSize(size_t bytes, char* out, size_t outSize) + { + if (bytes >= 1024 * 1024) + snprintf(out, outSize, "%.2f MB", bytes / (1024.0 * 1024.0)); + else if (bytes >= 1024) + snprintf(out, outSize, "%zu KB", bytes / 1024); + else + snprintf(out, outSize, "%zu B", bytes); + } + + enum class ContinuationAction { Continue, Exit, Error }; + ContinuationAction parseArguments(int argc, char** argv) + { + // Help is answered before anything else is acted on, so that asking for it + // never attaches to a process or takes a snapshot along the way. + for (int i = 1; i < argc; ++i) { + std::string_view arg = argv[i]; + if (arg != "--help" && arg != "-h") + continue; + if (i + 1 >= argc) { + printUsage(stdout); + return ContinuationAction::Exit; + } + Lexer lex(argv[i + 1]); + return handleHelp(lex) ? ContinuationAction::Exit : ContinuationAction::Error; + } + + for (int i = 1; i < argc; ++i) { + const char* argText = argv[i]; + std::string_view arg = argText; + const char* pidText = nullptr; + if (arg == "--pid" || arg == "-p") { + if (i + 1 >= argc) { + fprintf(stderr, "mya: %s requires an argument\n", argText); + return ContinuationAction::Error; + } + pidText = argv[++i]; + } else if (arg.starts_with("--pid=")) + pidText = argText + 6; + else if (arg.starts_with("-p") && arg.size() > 2) + pidText = argText + 2; // "-p12345" + else { + fprintf(stderr, "mya: Unknown option '%s'\n", argText); + return ContinuationAction::Error; + } + + pid_t pid = -1; + Lexer lex(pidText); + if (!lex.consumePID(pid) || !lex.atEnd()) { + fprintf(stderr, "mya: Invalid PID '%s'\n", pidText); + return ContinuationAction::Error; + } + + attachAndSnapshot(pid); + } + return ContinuationAction::Continue; + } + + void attach(pid_t pid) + { + RefPtr process; + auto existing = m_processes.find(pid); + if (existing != m_processes.end()) + process = existing->value; + else { + process = Process::create(pid); + m_processes.add(pid, process); + } + + if (!process->attach()) + return; + + if (m_currentProcess && m_currentProcess != process) + m_currentProcess->detach(); + + m_currentProcess = WTF::move(process); + printf("Attached to %d\n", static_cast(m_currentProcess->pid())); + } + + void detach() + { + if (!m_currentProcess) { + fputs("Not attached to any process.\n", stdout); + return; + } + pid_t pid = m_currentProcess->pid(); + m_currentProcess->detach(); + m_currentProcess = nullptr; + printf("Detached from %d\n", static_cast(pid)); + } + + // `mya --pid ` and `snapshot --pid ` both attach then snapshot. + void attachAndSnapshot(pid_t pid) + { + attach(pid); + if (m_currentProcess && m_currentProcess->pid() == pid) + captureSnapshot(); + } + + void captureSnapshot() + { + if (!m_currentProcess) { + fputs("Unable to capture snapshot. Not attached to any process. Use `attach` command or specify `--pid` argument for the snapshot command.\n", stderr); + return; + } + auto snapshot = WTF::makeUnique(m_currentProcess); + if (!snapshot->isValid()) + return; // The Snapshot constructor already logged the failure. + unsigned id = snapshot->id(); + // The map owns the Snapshot and the list only records capture order. + Snapshot* node = snapshot.get(); + m_snapshotsById.add(id, WTF::move(snapshot)); + m_snapshots.append(node); + printf("Captured Snapshot #%u of %d\n", id, static_cast(m_currentProcess->pid())); + useSnapshot(id); // Capturing switches to the new snapshot. + } + + // Sets the current snapshot used by subsequent commands. + void useSnapshot(unsigned id) + { + if (!snapshotById(id)) { + fprintf(stderr, "mya: No snapshot #%u\n", id); + return; + } + if (m_currentSnapshot) { + if (m_currentSnapshot == id) + printf("Already using snapshot %u\n", id); + else + printf("Switching to using snapshot %u\n", id); + } + m_currentSnapshot = id; + } + + // Returns the snapshot with the given id, or nullptr if there is none. + Snapshot* snapshotById(unsigned id) const + { + auto entry = m_snapshotsById.find(id); + return entry != m_snapshotsById.end() ? entry->value.get() : nullptr; + } + + void listSnapshots() + { + if (m_snapshots.isEmpty()) { + fputs("No snapshots.\n", stdout); + return; + } + for (Snapshot* snapshot = m_snapshots.head(); snapshot; snapshot = snapshot->next()) { + // Mark the snapshot currently in use. + const char* marker = snapshot->id() == m_currentSnapshot ? "*" : " "; + printf("%s #%u: pid %d\n", marker, snapshot->id(), static_cast(snapshot->process()->pid())); + } + } + + void snapshotInfo(unsigned id) + { + Snapshot* snapshot = snapshotById(id); + if (!snapshot) { + fprintf(stderr, "mya: No snapshot #%u\n", id); + return; + } + printf("Snapshot #%u: pid %d, corpse %s\n", id, + static_cast(snapshot->process()->pid()), snapshot->isValid() ? "valid" : "invalid"); + } + + void snapshotDelete(unsigned id) + { + Snapshot* snapshot = snapshotById(id); + if (!snapshot) { + fprintf(stderr, "mya: No snapshot #%u\n", id); + return; + } + // Unlink before dropping the owning entry: the list does not own its + // nodes, so it must not be left pointing at a destroyed Snapshot. + m_snapshots.remove(snapshot); + m_snapshotsById.remove(id); + if (id == m_currentSnapshot) + m_currentSnapshot = 0; + printf("Deleted Snapshot #%u.\n", id); + } + + void snapshotDiff(unsigned a, unsigned b) + { + if (!snapshotById(a)) { + fprintf(stderr, "mya: No snapshot #%u\n", a); + return; + } + if (!snapshotById(b)) { + fprintf(stderr, "mya: No snapshot #%u\n", b); + return; + } + printf("Snapshot diff #%u vs #%u is not implemented yet.\n", a, b); + } + + // `lex` is positioned after the "snapshot" command word. + void handleSnapshot(Lexer lex) + { + if (lex.atEnd()) { + captureSnapshot(); + return; + } + // A bare number switches to that snapshot e.g. "snapshot 3". + if (isASCIIDigit(static_cast(lex.peek()))) { + unsigned number = 0; + if (!lex.consumeUint32(number) || !lex.atEnd()) { + fputs("Usage: snapshot \n", stderr); + return; + } + useSnapshot(number); + return; + } + if (lex.consumeToken("--pid") || lex.consumeToken("-p")) { + pid_t pid = -1; + if (!lex.consumePID(pid) || !lex.atEnd()) { + fputs("Usage: snapshot [--pid|-p] \n", stderr); + return; + } + attachAndSnapshot(pid); + return; + } + if (lex.consumeToken("li") || lex.consumeToken("list")) { + listSnapshots(); + return; + } + if (lex.consumeToken("inf") || lex.consumeToken("info")) { + unsigned number = 0; + if (!lex.consumeUint32(number) || !lex.atEnd()) { + fputs("Usage: snapshot info \n", stderr); + return; + } + snapshotInfo(number); + return; + } + if (lex.consumeToken("del") || lex.consumeToken("delete")) { + unsigned number = 0; + if (!lex.consumeUint32(number) || !lex.atEnd()) { + fputs("Usage: snapshot delete \n", stderr); + return; + } + snapshotDelete(number); + return; + } + if (lex.consumeToken("diff")) { + unsigned a = 0; + unsigned b = 0; + if (!lex.consumeUint32(a) || !lex.consumeUint32(b) || !lex.atEnd()) { + fputs("Usage: snapshot diff \n", stderr); + return; + } + snapshotDiff(a, b); + return; + } + std::string_view token = lex.nextToken(); + fprintf(stderr, "mya: Unknown snapshot subcommand '%.*s'\n", + static_cast(token.length()), token.data()); + } + + // Lists the threads captured in the snapshot currently in use. + void listThreads() + { + Snapshot* snapshot = snapshotById(m_currentSnapshot); + if (!snapshot) { + fputs("No snapshot in use. Capture one with `snapshot`, or select one with `snapshot `.\n", stderr); + return; + } + + const Vector& threads = snapshot->threads(); + if (threads.isEmpty()) { + fputs("No threads.\n", stdout); + return; + } + + printf("Threads in snapshot #%u (pid %d):\n", snapshot->id(), static_cast(snapshot->process()->pid())); + + // Build the rows as text first so each column can be sized to its widest entry. + static constexpr size_t columnCount = 12; + static const char* const headings[columnCount] = { + "INDEX", "TID", "STATE", "USER(ms)", "SYS(ms)", "SP", "STACK", "SIZE", + "PAGES", "RESIDENT", "DIRTY", "NAME" + }; + static const bool rightAligned[columnCount] = { + true, false, false, true, true, false, false, true, true, true, true, false + }; + + struct Row { + std::string cells[columnCount]; + }; + Vector rows; + rows.reserveCapacity(threads.size()); + + char buffer[64]; + for (size_t i = 0; i < threads.size(); ++i) { + const Thread& thread = threads[i]; + Row row; + + snprintf(buffer, sizeof(buffer), "%zu", i + 1); + row.cells[0] = buffer; + snprintf(buffer, sizeof(buffer), "0x%llx", static_cast(thread.id())); + row.cells[1] = buffer; + row.cells[2] = thread.runStateDescription(); + snprintf(buffer, sizeof(buffer), "%.3f", thread.userTimeUsec() / 1000.0); + row.cells[3] = buffer; + snprintf(buffer, sizeof(buffer), "%.3f", thread.systemTimeUsec() / 1000.0); + row.cells[4] = buffer; + if (thread.stackPointer()) { + snprintf(buffer, sizeof(buffer), "0x%llx", + thread.stackPointer().toMachVMAddress()); + row.cells[5] = buffer; + } else + row.cells[5] = "-"; + if (thread.hasStack()) { + const auto& stack = thread.stackRegion(); + snprintf(buffer, sizeof(buffer), "0x%llx-0x%llx", + stack.base().toMachVMAddress(), + stack.end().toMachVMAddress()); + row.cells[6] = buffer; + formatByteSize(stack.size(), buffer, sizeof(buffer)); + row.cells[7] = buffer; + snprintf(buffer, sizeof(buffer), "%llu", + static_cast(stack.pageCount())); + row.cells[8] = buffer; + snprintf(buffer, sizeof(buffer), "%llu", + static_cast(stack.residentPageCount())); + row.cells[9] = buffer; + snprintf(buffer, sizeof(buffer), "%llu", + static_cast(stack.dirtyPageCount())); + row.cells[10] = buffer; + } else { + row.cells[6] = "-"; + row.cells[7] = "-"; + row.cells[8] = "-"; + row.cells[9] = "-"; + row.cells[10] = "-"; + } + row.cells[11] = thread.name().empty() ? "-" : thread.name(); + + rows.append(WTF::move(row)); + } + + size_t widths[columnCount]; + for (size_t column = 0; column < columnCount; ++column) { + widths[column] = strlen(headings[column]); + for (const Row& row : rows) + widths[column] = std::max(widths[column], row.cells[column].length()); + } + + auto printRow = [&](auto&& cellAt) { + fputs(" ", stdout); + for (size_t column = 0; column < columnCount; ++column) { + if (column) + fputs(" ", stdout); + const char* text = cellAt(column); + // The last column needs no padding, which also avoids trailing + // whitespace on every line. + if (column == columnCount - 1) + fputs(text, stdout); + else if (rightAligned[column]) + printf("%*s", static_cast(widths[column]), text); + else + printf("%-*s", static_cast(widths[column]), text); + } + putchar('\n'); + }; + + printRow([&](size_t column) { return headings[column]; }); + for (const Row& row : rows) + printRow([&](size_t column) { return row.cells[column].c_str(); }); + } + + // Dispatches the `thread ...` subcommands. `lex` is positioned after the + // "thread" command word. + void handleThread(Lexer lex) + { + // Listing is the default, so a bare `thread` lists too. + if (lex.atEnd() || lex.consumeToken("li") || lex.consumeToken("list")) { + if (!lex.atEnd()) { + fputs("Usage: thread list\n", stderr); + return; + } + listThreads(); + return; + } + std::string_view token = lex.nextToken(); + fprintf(stderr, "mya: Unknown thread subcommand '%.*s'\n", + static_cast(token.length()), token.data()); + } + + // Dispatches `p[/] `. The only expression understood so + // far is `&`, which resolves the symbol in the snapshot in use. + // `format` is the text after the '/', empty when none was given. + void handlePrint(std::string_view format, Lexer lex) + { + bool hex = false; + if (!format.empty()) { + if (format == "x") + hex = true; + else if (format != "d") { + fprintf(stderr, "mya: Unknown print format '%.*s'; use x or d\n", + static_cast(format.length()), format.data()); + return; + } + } + + Snapshot* snapshot = snapshotById(m_currentSnapshot); + if (!snapshot) { + fputs("No snapshot in use. Capture one with `snapshot`, or select one with `snapshot `.\n", stderr); + return; + } + + // Taking a symbol's address is all we can do without type information. + if (!lex.consumeChar('&')) { + fputs("Usage: p[/x] &\n", stderr); + return; + } + std::string_view token = lex.nextToken(); + if (token.empty() || !lex.atEnd()) { + fputs("Usage: p[/x] &\n", stderr); + return; + } + + std::string name(token); + Address address = snapshot->symbol(name.c_str()); + if (!address) { + fprintf(stderr, "mya: No symbol '%s' in snapshot #%u\n", name.c_str(), snapshot->id()); + return; + } + if (hex) + printf("&%s = 0x%llx\n", name.c_str(), address.toMachVMAddress()); + else + printf("&%s = %llu\n", name.c_str(), address.toMachVMAddress()); + } + + // Releases resources without extra output. Dropping the current selection + // and clearing the containers runs ~Process / ~Snapshot, which release the + // task and corpse ports. Idempotent: safe from the quit path and destructor. + void cleanup() + { + m_currentProcess = nullptr; + m_processes.clear(); + // Unlink the non-owning list before destroying the Snapshots it points at. + m_snapshots.clear(); + m_snapshotsById.clear(); + if (m_historyFile) { + fclose(m_historyFile); + m_historyFile = nullptr; + } + if (m_historyDirDescriptor >= 0) { + close(m_historyDirDescriptor); + m_historyDirDescriptor = -1; + } + } + + // Prompts for confirmation before quitting. Enter (empty) defaults to yes. + bool confirmQuit() + { + for (;;) { + std::string response; +#if HAVE(READLINE) + char* input = readline("Really quit? [Y/n] "); + if (!input) { + putchar('\n'); + return true; // EOF: treat as yes. + } + response = input; + free(input); +#else + fputs("Really quit? [Y/n] ", stdout); + fflush(stdout); + char buffer[64]; + if (!fgets(buffer, sizeof(buffer), stdin)) { + putchar('\n'); + return true; // EOF: treat as yes. + } + // Without a newline the answer was longer than the buffer, and the rest + // would be read as the answer to the next prompt. Discard it. + if (!std::string_view(buffer).contains('\n')) { + int discarded = 0; + while ((discarded = getchar()) != '\n' && discarded != EOF) { } + } + response = buffer; +#endif + size_t start = 0; + while (start < response.size() && isASCIIWhitespace(static_cast(response[start]))) + ++start; + size_t stop = response.size(); + while (stop > start && isASCIIWhitespace(static_cast(response[stop - 1]))) + --stop; + response = response.substr(start, stop - start); + + if (response.empty() || response[0] == 'y' || response[0] == 'Y') + return true; + if (response[0] == 'n' || response[0] == 'N') + return false; + fputs("Please answer 'y' or 'n'.\n", stdout); + } + } + + void printStatus() + { + if (m_currentProcess) + printf("Attached to pid %d\n", static_cast(m_currentProcess->pid())); + else + fputs("Not attached to any process.\n", stdout); + + if (Snapshot* snapshot = snapshotById(m_currentSnapshot)) + printf("Using snapshot %u of pid %d\n", snapshot->id(), static_cast(snapshot->process()->pid())); + else + fputs("No snapshot in use.\n", stdout); + } + + void printHistory() + { + if (!m_history.size()) { + printf("History is empty.\n"); + return; + } + for (size_t i = 0; i < m_history.size(); ++i) + printf("%5zu %s\n", i + 1, m_history[i].c_str()); + } + + // Drops the `count` oldest entries. + void clearHistory(unsigned count) + { + if (!count) { + fputs("Nothing to do for clearing 0 history entries.\n", stdout); + return; + } + if (m_history.empty()) { + fputs("History is already empty.\n", stdout); + return; + } + unsigned removeCount = count >= m_history.size() ? safeCast(m_history.size()) : count; + m_history.erase(m_history.begin(), m_history.begin() + removeCount); +#if HAVE(READLINE) + // readline has no way to drop individual entries, so rebuild its history + // from the cache to keep the arrow keys in sync. + clear_history(); + for (const std::string& command : m_history) + add_history(command.c_str()); +#endif + if (m_historyFile && !rewriteHistoryFile()) { + fputs("mya: Failed to clear history file.\n", stderr); + return; + } + if (m_history.empty()) { + if (removeCount == 1) + printf("Cleared 1 history entry.\n"); + else + printf("Cleared %u history entries.\n", removeCount); + } else if (removeCount == 1) + printf("Cleared the oldest history entry.\n"); + else + printf("Cleared the %u oldest history entries.\n", removeCount); + } + + void printHistorySize() + { + printf("History holds %zu of %u entries.\n", m_history.size(), m_maxHistoryEntries); + } + + // Sets how many entries the history keeps, purging the oldest if the new + // capacity is smaller than what is currently stored. + void setMaxHistorySize(unsigned capacity) + { + if (capacity < minHistorySize) { + capacity = minHistorySize; + printf("Minimum history size is %u.\n", minHistorySize); + } + if (m_maxHistoryEntries == capacity) { + printf("Maximum history size is already %u.\n", m_maxHistoryEntries); + return; + } + m_maxHistoryEntries = capacity; + boundReadlineHistory(); + if (m_history.size() > m_maxHistoryEntries) { + m_history.erase(m_history.begin(), m_history.end() - m_maxHistoryEntries); +#if HAVE(READLINE) + clear_history(); + for (const std::string& command : m_history) + add_history(command.c_str()); +#endif + } + if (!rewriteHistoryFile()) + fputs("mya: The new size applies to this session only.\n", stderr); + printHistorySize(); + } + + // Dispatches the `history ...` subcommands. `lex` is positioned after the + // "history" command word. + void handleHistory(Lexer lex) + { + if (lex.atEnd()) { + printHistory(); + return; + } + if (lex.consumeToken("clear")) { + unsigned count = UINT_MAX; // Default to "all". + if (!lex.atEnd()) { + unsigned parsed = 0; + if (!lex.consumeUint32(parsed) || !lex.atEnd()) { + fputs("Usage: history clear []\n", stderr); + return; + } + count = parsed; + } + clearHistory(count); + return; + } + if (lex.consumeToken("size")) { + if (lex.atEnd()) { + printHistorySize(); + return; + } + unsigned capacity = 0; + if (!lex.consumeUint32(capacity) || !lex.atEnd()) { + fputs("Usage: history size []\n", stderr); + return; + } + setMaxHistorySize(capacity); + return; + } + std::string_view token = lex.nextToken(); + fprintf(stderr, "mya: Unknown history subcommand '%.*s'\n", + static_cast(token.length()), token.data()); + } + + // Resolves a history reference ("!!" or "!") to a stored command and + // replays it. `lex` is positioned after the leading '!'; `line` is the whole + // input, used for error reporting. + void replayHistory(const char* line, Lexer lex) + { + std::string command; + if (lex.consumeChar('!') && lex.atEnd()) { + if (m_history.empty()) { + fputs("mya: No commands in history\n", stderr); + return; + } + command = m_history.back(); + } else { + unsigned index = 0; + if (!lex.consumeUint32(index) || !lex.atEnd() || index > m_history.size()) { + fprintf(stderr, "mya: %s: event not found\n", line); + return; + } + if (!index) { + fprintf(stderr, "mya: %s: invalid history entry\n", line); + return; + } + command = m_history[index - 1]; + } + // Echo the resolved command, then run it as if it had been typed. The + // replayed command records itself; the "!" reference is not recorded. + printf("%s\n", command.c_str()); + handleLine(command.c_str()); + } + + static bool isRunningAsRoot() { return !geteuid(); } + + // The directory that holds the history file, empty if the user has no home + // directory to put it in. + // + // We deliberately keep root (when run with sudo)'s history file distinct from + // the non-root user's. This is better for security (root is not dependent on + // non-root user data), and does not block the non-root user from accessing + // their history if the last mya run was via sudo and the history file was + // updated by root (and ownership changed). + static std::string historyDirectory() + { + const char* home = nullptr; + if (isRunningAsRoot()) { + if (const struct passwd* entry = getpwuid(0)) + home = entry->pw_dir; + } else { + home = getenv("HOME"); + if (!home || !*home) { + if (const struct passwd* entry = getpwuid(getuid())) + home = entry->pw_dir; + } + } + if (!home || !*home) + return { }; + + std::string directory = home; + if (directory.back() != '/') + directory += '/'; + directory += historyDirName; + return directory; + } + + void boundReadlineHistory() + { +#if HAVE(READLINE) + // libedit only applies the bound when an entry is added, so lowering it does + // not shorten the existing list: callers that shrink the cache must rebuild + // readline's list as well for the change to take effect immediately. + stifle_history(safeCast(m_maxHistoryEntries)); +#endif + } + + // Opens the history file for read+write, creating it if absent, and loads any + // stored commands into the cache. If it cannot be opened, the cache stays in + // memory only for the session. + // + // The file lives under the user's home directory, not the working directory: + // mya carries a debugger entitlement and its own usage suggests running it as + // root, so it must not be steered into writing through a path controlled by + // whoever owns the directory it happens to be started in. Both path + // components are opened O_NOFOLLOW, so a symlink planted at either one is + // refused rather than followed, and the file is never opened with O_TRUNC. + void openHistory() + { + boundReadlineHistory(); + + std::string directory = historyDirectory(); + if (directory.empty()) { + fputs("mya: No home directory, so command history will not be saved.\n", stderr); + return; + } + + if (isRunningAsRoot()) { + fprintf(stderr, "mya: Running as root: using history file %s/%s.\n", + directory.c_str(), historyFileName); + } + + if (mkdir(directory.c_str(), 0700) && errno != EEXIST) { + fprintf(stderr, "mya: Could not create %s: %s\n", directory.c_str(), strerror(errno)); + return; + } + + int directoryDescriptor = open(directory.c_str(), O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (directoryDescriptor < 0) { + fprintf(stderr, "mya: Could not open %s: %s\n", directory.c_str(), strerror(errno)); + return; + } + + int fileDescriptor = openat(directoryDescriptor, historyFileName, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 0600); + if (fileDescriptor < 0) { + fprintf(stderr, "mya: Could not open %s/%s: %s\n", directory.c_str(), historyFileName, strerror(errno)); + close(directoryDescriptor); + return; + } + + // Anything other than a regular file is not something mya wrote: reading a + // FIFO here would block the shell before it ever prompted. So, we decline to open + // any non-regular files. + struct stat status; + if (fstat(fileDescriptor, &status) || !S_ISREG(status.st_mode)) { + fprintf(stderr, "mya: %s/%s is not a regular file, so command history will not be saved.\n", + directory.c_str(), historyFileName); + close(fileDescriptor); + close(directoryDescriptor); + return; + } + + m_historyFile = fdopen(fileDescriptor, "r+"); + if (!m_historyFile) { + close(fileDescriptor); + close(directoryDescriptor); + return; + } + + // Held for the session: rewriting the file creates and renames through this + // descriptor, so the replacement lands in the directory that was checked + // here rather than wherever the path may point by then. + m_historyDirDescriptor = directoryDescriptor; + + loadHistory(); + } + + // Reads the cap out of a "max entries " header line. Returns 0 if `line` does not + // contain the header, which means the file is corrupted. + static unsigned parseMaxEntriesHeader(const char* line) + { + size_t prefixLength = strlen(maxEntriesHeaderPrefix); + if (!std::string_view(line).starts_with(maxEntriesHeaderPrefix)) + return 0; + Lexer lex(line + prefixLength); + unsigned entries = 0; + if (!lex.consumeUint32<1>(entries) || !lex.atEnd()) + return 0; + // We deliberately allow reading a capacity value below minHistorySize so that we can + // print a meaningful error message about it in the caller. + return entries; + } + + void loadHistory() + { + if (!m_historyFile) + return; + rewind(m_historyFile); + + char buffer[4096]; + unsigned capacity = 0; + if (fgets(buffer, sizeof(buffer), m_historyFile)) { + buffer[strcspn(buffer, "\n")] = '\0'; + capacity = parseMaxEntriesHeader(buffer); + if (!capacity) { + fprintf(stderr, "mya: Corrupted file: ~/%s/%s does not start with a valid header (\"%s\"); starting a new one.\n", + historyDirName, historyFileName, maxEntriesHeaderPrefix); + } else if (capacity < minHistorySize) { + fprintf(stderr, "mya: Corrupted file: ~/%s/%s header asks for fewer than the minimum %u entries;" + " starting a new one.\n", historyDirName, historyFileName, minHistorySize); + capacity = 0; // Treat as error. + } + } + if (!capacity) { + rewriteHistoryFile(); // Invalid header. Reset the history file. + return; + } + m_maxHistoryEntries = capacity; + boundReadlineHistory(); + + Vector entries; + while (fgets(buffer, sizeof(buffer), m_historyFile)) { + buffer[strcspn(buffer, "\n")] = '\0'; + if (!buffer[0]) + continue; + if (isReplayCommand(buffer)) + continue; // A ! replay command in history is invalid and not allowed. Skip. + entries.append(buffer); + } + m_entriesInHistoryFile = safeCast(entries.size()); + + // The cache never holds more than the capacity, however much the file holds. + unsigned keep = std::min(m_entriesInHistoryFile, m_maxHistoryEntries); + for (size_t i = entries.size() - keep; i < entries.size(); ++i) { + m_history.push_back(entries[i]); +#if HAVE(READLINE) + add_history(entries[i].c_str()); +#endif + } + + // Seek to the end so later commands append, and to satisfy the C rule + // that a positioning call separates a read from a following write. + if (fseek(m_historyFile, 0, SEEK_END)) + fallBackToMemoryOnly("Could not read the history file", errno); + } + + // Report the failure condition and switch to in-memory cache only history. + // The history file itself is left exactly as it was, and whatever was already + // read from it stays in the cache. + void fallBackToMemoryOnly(const char* what, int error) + { + fprintf(stderr, "mya: %s: %s\n", what, strerror(error)); + fputs("mya: Command history is kept in memory only from here, and the saved" + " history is left as it is.\n", stderr); + if (m_historyFile) { + fclose(m_historyFile); + m_historyFile = nullptr; + } + if (m_historyDirDescriptor >= 0) { + close(m_historyDirDescriptor); + m_historyDirDescriptor = -1; + } + } + + // Replaces the history file as a transaction i.e. the file either has the new + // history or remains the old one if something went wrong. It is never left half + // modified. This is done by writing the new file completely before replacing the + // old history file with it. + // + // In the event something went wrong, the in-memory cache retains its state, and + // may become out of sync with the history file. + bool rewriteHistoryFile() + { + if (!m_historyFile || m_historyDirDescriptor < 0) + return false; + + // Qualified by pid so two mya instances cannot land on the same temporary. + char temporaryName[64]; + snprintf(temporaryName, sizeof(temporaryName), "%s.%d.tmp", historyFileName, + static_cast(getpid())); + + int descriptor = openat(m_historyDirDescriptor, temporaryName, + O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600); + if (descriptor < 0 && errno == EEXIST) { + // Left behind by a run that died between creating and renaming. + unlinkat(m_historyDirDescriptor, temporaryName, 0); + descriptor = openat(m_historyDirDescriptor, temporaryName, + O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600); + } + if (descriptor < 0) { + fallBackToMemoryOnly("Could not create a temporary history file", errno); + return false; + } + + FILE* replacement = fdopen(descriptor, "w+"); + if (!replacement) { + int error = errno; + close(descriptor); + unlinkat(m_historyDirDescriptor, temporaryName, 0); + fallBackToMemoryOnly("Could not rewrite the history file", error); + return false; + } + + fprintf(replacement, "%s%u\n", maxEntriesHeaderPrefix, m_maxHistoryEntries); + for (const std::string& command : m_history) + fprintf(replacement, "%s\n", command.c_str()); + + // Commit the contents before publishing them, so a crash cannot leave the + // rename pointing at a file that was never written. + int error = 0; + if (fflush(replacement) || fsync(fileno(replacement))) + error = errno; + else if (ferror(replacement)) + error = EIO; + if (!error && renameat(m_historyDirDescriptor, temporaryName, m_historyDirDescriptor, historyFileName)) + error = errno; + if (error) { + fclose(replacement); + unlinkat(m_historyDirDescriptor, temporaryName, 0); + fallBackToMemoryOnly("Could not rewrite the history file", error); + return false; + } + + // The rename published the temporary file, so it is the history file now. + fclose(m_historyFile); + m_historyFile = replacement; + m_entriesInHistoryFile = safeCast(m_history.size()); + if (fseek(m_historyFile, 0, SEEK_END)) { + fallBackToMemoryOnly("Could not rewrite the history file", errno); + return false; + } + return true; + } + + static bool isReplayCommand(const char* line) + { + Lexer lex(line); + return lex.peek() == '!'; + } + + void recordCommand(const char* line) + { + // Do not allow replay commands in the history. They just pollute the history, and + // add recursion complexities in the replay execution code, which we want to prevent. + if (isReplayCommand(line)) + return; + + // Only filter an immediate repeat of the previous command. + if (!m_history.empty() && m_history.back() == line) + return; + + m_history.push_back(line); +#if HAVE(READLINE) + add_history(line); +#endif + if (m_history.size() > m_maxHistoryEntries) + m_history.erase(m_history.begin()); + + if (!m_historyFile) + return; + + fprintf(m_historyFile, "%s\n", line); + int error = 0; + if (fflush(m_historyFile)) + error = errno; + else if (ferror(m_historyFile)) + error = EIO; + if (error) { + fallBackToMemoryOnly("Could not append to the history file", error); + return; + } + ++m_entriesInHistoryFile; + // The sum cannot overflow: the capacity only ever comes from Lexer::consumeUint32, + // which rejects anything above INT_MAX, leaving room for the overflow + // allowance on top. + if (m_entriesInHistoryFile >= m_maxHistoryEntries + maxOverflowEntries) + rewriteHistoryFile(); + } + + void handleLine(const char* line) + { + Lexer lex(line); + if (lex.atEnd()) + return; // Blank line: not a command, not an error. + + // History replay ("!!" / "!") is expanded before command dispatch. + if (lex.consumeChar('!')) + return replayHistory(line, lex); + + std::string_view word = lex.nextToken(); + // `p` takes an lldb-style format suffix, as in "p/x", so the command and + // its format arrive as one token. + std::string_view command = word; + std::string_view format; + if (size_t slash = word.find('/'); slash != std::string_view::npos) { + command = word.substr(0, slash); + format = word.substr(slash + 1); + } + + auto is = [&](const char* name) { + return word == name; + }; + + if (is("help")) { + handleHelp(lex); + return; + } + if (is("q") || is("quit") || is("exit")) { + m_isQuitting = confirmQuit(); + return; + } + if (is("st") || is("status")) { + recordCommand(line); + printStatus(); + return; + } + if (is("hi") || is("hist") || is("history")) { + // A bare `history` only lists the history. Recording it would make + // the last entry of every listing be the command that asked for it. + if (!lex.atEnd()) + recordCommand(line); + handleHistory(lex); + return; + } + if (is("detach")) { + recordCommand(line); + detach(); + return; + } + if (is("attach")) { + recordCommand(line); + // Optional "--pid"/"-p" before the number: "attach --pid 42" == "attach 42". + if (!lex.consumeToken("--pid")) + lex.consumeToken("-p"); + pid_t pid = -1; + if (!lex.consumePID(pid) || !lex.atEnd()) { + fputs("Usage: attach [--pid|-p] \n", stderr); + return; + } + attach(pid); + return; + } + if (is("sn") || is("snap") || is("snapshot")) { + recordCommand(line); + handleSnapshot(lex); + return; + } + if (is("th") || is("thread")) { + recordCommand(line); + handleThread(lex); + return; + } + if (command == "p" || command == "print") { + recordCommand(line); + handlePrint(format, lex); + return; + } + + recordCommand(line); + fprintf(stderr, "mya: Unknown command '%.*s'\n", static_cast(word.length()), word.data()); + } + + void runInteractive() + { +#if HAVE(READLINE) + for (;;) { + char* line = readline(prompt); + if (!line) { + putchar('\n'); + break; + } + handleLine(line); + free(line); + if (m_isQuitting) + break; + } +#else + char line[4096]; + fputs(prompt, stdout); + fflush(stdout); + while (fgets(line, sizeof(line), stdin)) { + line[strcspn(line, "\n")] = '\0'; + handleLine(line); + if (m_isQuitting) + break; + fputs(prompt, stdout); + fflush(stdout); + } + putchar('\n'); +#endif + cleanup(); // About to quit. + } + + std::vector m_history; + unsigned m_maxHistoryEntries { defaultMaxHistoryEntries }; + unsigned m_entriesInHistoryFile { 0 }; // Actual number of commands in the file (may exceed target capacity). + FILE* m_historyFile { nullptr }; + int m_historyDirDescriptor { -1 }; + HashMap> m_processes; + // m_snapshotsById owns the Snapshots; m_snapshots only records capture order. + HashMap> m_snapshotsById; + DoublyLinkedList m_snapshots; + RefPtr m_currentProcess; + unsigned m_currentSnapshot { 0 }; // Snapshot id in use; 0 means none. + bool m_isQuitting { false }; +}; + +} // namespace Mya + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + +int main(int argc, char** argv) +{ +#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) + return Mya::Shell().run(argc, argv); +#else + UNUSED_PARAM(argc); + UNUSED_PARAM(argv); + printf("Not supported platform for mya\n"); + return 1; +#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR) +} diff --git a/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp index 6b2c96688dd9..03d40b0d33e4 100644 --- a/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp +++ b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp @@ -34,6 +34,10 @@ #if USE(BUN_JSC_ADDITIONS) #include "SyntheticModuleRecord.h" #endif +#if ENABLE(WEBASSEMBLY) +#include "JSWebAssemblyGlobal.h" +#include "WebAssemblyModuleRecord.h" +#endif namespace JSC { @@ -207,6 +211,17 @@ bool JSModuleNamespaceObject::getOwnPropertySlotCommon(JSGlobalObject* globalObj return false; } +#if ENABLE(WEBASSEMBLY) + if (is(exportEntry.moduleRecord.get())) { + if (auto* wasmGlobal = dynamicDowncast(value); wasmGlobal && wasmGlobal->global()->mutability() == Wasm::Mutability::Mutable) { + value = wasmGlobal->global()->get(globalObject); + RETURN_IF_EXCEPTION(scope, false); + slot.setValue(this, static_cast(PropertyAttribute::DontDelete), value); + return true; + } + } +#endif + slot.setValueModuleNamespace(this, static_cast(PropertyAttribute::DontDelete), value, environment, scopeOffset); return true; } diff --git a/Source/JavaScriptCore/shell/CMakeLists.txt b/Source/JavaScriptCore/shell/CMakeLists.txt index 01a69510b43b..83d560adb6e0 100644 --- a/Source/JavaScriptCore/shell/CMakeLists.txt +++ b/Source/JavaScriptCore/shell/CMakeLists.txt @@ -29,6 +29,24 @@ if (ENABLE_FUZZILLI) list(APPEND jsc_SOURCES ../fuzzilli/Fuzzilli.cpp) endif () +# mya analyzes process corpses through Mach task APIs, so it only builds on +# Apple platforms. Its sources do not compile elsewhere. +if (APPLE) + set(mya_SOURCES ../mya/mya.cpp) + set(mya_FRAMEWORKS + JavaScriptCore + WTF + bmalloc + ) + + set(mya_PRIVATE_INCLUDE_DIRECTORIES + $ + ) + + # The corpse support mya uses lives in the tools static library. + set(mya_LIBRARIES JavaScriptCoreTools edit) +endif () + WEBKIT_EXECUTABLE_DECLARE(jsc) if (USE_BUN_JSC_ADDITIONS) @@ -63,6 +81,10 @@ if (USE_BUN_JSC_ADDITIONS) WEBKIT_EXECUTABLE_DECLARE(testFFI) endif () +if (APPLE) + WEBKIT_EXECUTABLE_DECLARE(mya) +endif () + if (DEVELOPER_MODE) set(testapi_SOURCES ../API/tests/CompareAndSwapTest.cpp @@ -123,6 +145,29 @@ if (DEVELOPER_MODE) set(testdfg_PRIVATE_INCLUDE_DIRECTORIES ${jsc_PRIVATE_INCLUDE_DIRECTORIES}) set(testdfg_FRAMEWORKS ${jsc_FRAMEWORKS}) + # The tools library and its tests are only relevant for Apple platforms. + if (APPLE) + set(testLibJSCTools_SOURCES + ../corpse/tests/CorpseAddressTest.cpp + ../corpse/tests/CorpseByteParserTest.cpp + ../corpse/tests/CorpseExportsTrieTest.cpp + ../corpse/tests/CorpseProcessTest.cpp + ../corpse/tests/CorpseRegionTest.cpp + ../corpse/tests/CorpseSnapshotTest.cpp + ../corpse/tests/CorpseSymbolTest.cpp + ../corpse/tests/CorpseThreadTest.cpp + ../corpse/tests/LibJSCToolsTestUtilities.cpp + ../corpse/tests/testLibJSCTools.cpp + ) + set(testLibJSCTools_DEFINITIONS ${jsc_PRIVATE_DEFINITIONS}) + set(testLibJSCTools_PRIVATE_INCLUDE_DIRECTORIES + ${jsc_PRIVATE_INCLUDE_DIRECTORIES} + ${JAVASCRIPTCORE_DIR}/corpse + ) + set(testLibJSCTools_FRAMEWORKS ${jsc_FRAMEWORKS}) + set(testLibJSCTools_LIBRARIES JavaScriptCoreTools) + endif () + set(testwasmdebugger_SOURCES ../wasm/debugger/testwasmdebugger.cpp @@ -155,6 +200,10 @@ if (DEVELOPER_MODE) WEBKIT_EXECUTABLE_DECLARE(testdfg) WEBKIT_EXECUTABLE_DECLARE(testwasmdebugger) + if (APPLE) + WEBKIT_EXECUTABLE_DECLARE(testLibJSCTools) + endif () + if (COMPILER_IS_GCC_OR_CLANG) WEBKIT_ADD_TARGET_CXX_FLAGS(testb3 -Wno-array-bounds) WEBKIT_ADD_TARGET_CXX_FLAGS(testair -Wno-array-bounds) @@ -175,6 +224,14 @@ if (SHOULD_INSTALL_JS_SHELL) install(TARGETS jsc DESTINATION "${LIBEXEC_INSTALL_DIR}") endif () +if (APPLE) + WEBKIT_EXECUTABLE(mya) + + if (SHOULD_INSTALL_JS_SHELL) + install(TARGETS mya DESTINATION "${LIBEXEC_INSTALL_DIR}") + endif () +endif () + if (DEVELOPER_MODE) WEBKIT_EXECUTABLE(testapi) WEBKIT_EXECUTABLE(testRegExp) @@ -184,6 +241,10 @@ if (DEVELOPER_MODE) WEBKIT_EXECUTABLE(testdfg) WEBKIT_EXECUTABLE(testwasmdebugger) + if (APPLE) + WEBKIT_EXECUTABLE(testLibJSCTools) + endif () + WEBKIT_ADD_PREFIX_HEADER(testapi ../JavaScriptCorePrefix.h PREFIX_NO_CODEGEN PREFIX_LANGUAGES CXX) WEBKIT_REUSE_PREFIX_HEADER(testb3 testapi ../JavaScriptCorePrefix.h PREFIX_LANGUAGES CXX) WEBKIT_REUSE_PREFIX_HEADER(testwasmdebugger testapi ../JavaScriptCorePrefix.h PREFIX_LANGUAGES CXX) diff --git a/Source/JavaScriptCore/shell/PlatformCocoa.cmake b/Source/JavaScriptCore/shell/PlatformCocoa.cmake index 06765386e803..3ebba0330703 100644 --- a/Source/JavaScriptCore/shell/PlatformCocoa.cmake +++ b/Source/JavaScriptCore/shell/PlatformCocoa.cmake @@ -14,6 +14,7 @@ set_source_files_properties(${testapi_OBJC_SOURCES} PROPERTIES ) WEBKIT_GENERATE_ENTITLEMENTS(jsc USING ../Scripts/process-entitlements.sh) +WEBKIT_GENERATE_ENTITLEMENTS(mya USING ../Scripts/process-entitlements.sh) if (DEVELOPER_MODE) WEBKIT_GENERATE_ENTITLEMENTS(testapi USING ../Scripts/process-entitlements.sh) WEBKIT_GENERATE_ENTITLEMENTS(testRegExp USING ../Scripts/process-entitlements.sh) @@ -21,5 +22,6 @@ if (DEVELOPER_MODE) WEBKIT_GENERATE_ENTITLEMENTS(testb3 USING ../Scripts/process-entitlements.sh) WEBKIT_GENERATE_ENTITLEMENTS(testair USING ../Scripts/process-entitlements.sh) WEBKIT_GENERATE_ENTITLEMENTS(testdfg USING ../Scripts/process-entitlements.sh) + WEBKIT_GENERATE_ENTITLEMENTS(testLibJSCTools USING ../Scripts/process-entitlements.sh) endif () diff --git a/Source/JavaScriptCore/wasm/WasmBBQJIT.cpp b/Source/JavaScriptCore/wasm/WasmBBQJIT.cpp index 77a7e16d2cc3..c5ab146354b4 100644 --- a/Source/JavaScriptCore/wasm/WasmBBQJIT.cpp +++ b/Source/JavaScriptCore/wasm/WasmBBQJIT.cpp @@ -3215,16 +3215,27 @@ PartialResult BBQJIT::addI32Extend8S(Value operand, Value& result) [[nodiscard]] PartialResult BBQJIT::addRefFunc(FunctionSpaceIndex index, Value& result) { - // FIXME: Emit this inline . - TypeKind returnType = TypeKind::Ref; + GPRReg resultGPR; + { + ScratchScope<1, 0> scratches(*this); + resultGPR = scratches.gpr(0); + + m_jit.load64(Address(GPRInfo::wasmContextInstancePointer, safeCast(JSWebAssemblyInstance::offsetOfFunctionWrapper(m_info, index))), resultGPR); + + JumpList slowPath = m_jit.branchTest64(ResultCondition::Zero, resultGPR); + MacroAssembler::Label done(m_jit); + m_slowPaths.append({ origin(), WTF::move(slowPath), WTF::move(done), copyBindings(), [index, resultGPR](BBQJIT&, CCallHelpers& jit) { + jit.prepareWasmCallOperation(GPRInfo::wasmContextInstancePointer); + jit.setupArguments(GPRInfo::wasmContextInstancePointer, TrustedImm32(static_cast(index))); + jit.callOperation(operationWasmRefFunc); + jit.move(GPRInfo::returnValueGPR, resultGPR); + } }); + } - Vector arguments = { - instanceValue(), - Value::fromI32(index) - }; - result = topValue(returnType); - emitCCall(&operationWasmRefFunc, arguments, result); + result = topValue(TypeKind::Ref); + bind(result, Location::fromGPR(resultGPR)); + LOG_INSTRUCTION("RefFunc", index, RESULT(result)); return { }; } diff --git a/Source/JavaScriptCore/wasm/WasmBBQJIT64.cpp b/Source/JavaScriptCore/wasm/WasmBBQJIT64.cpp index 9fa3ffba4628..75c02372110f 100644 --- a/Source/JavaScriptCore/wasm/WasmBBQJIT64.cpp +++ b/Source/JavaScriptCore/wasm/WasmBBQJIT64.cpp @@ -1611,22 +1611,6 @@ void BBQJIT::emitAllocateGCArrayUninitialized(GPRReg resultGPR, TypeSignatureInd [[nodiscard]] PartialResult BBQJIT::addArrayNewDefault(TypeSignatureIndex typeIndex, ExpressionType size, ExpressionType& result) { StorageType elementType = getArrayElementType(typeIndex); - // FIXME: We don't have a good way to fill V128s yet so just make a call. - if (elementType.unpacked().isV128()) { - Vector arguments = { - instanceValue(), - Value::fromI32(typeIndex.rawIndex()), - size, - }; - result = topValue(TypeKind::Arrayref); - emitCCall(operationWasmArrayNewEmpty, arguments, result); - - Location resultLocation = loadIfNecessary(result); - emitThrowOnNullReference(ExceptionType::BadArrayNew, resultLocation); - - LOG_INSTRUCTION("ArrayNewDefault", typeIndex, size, RESULT(result)); - return { }; - } GPRReg resultGPR; { @@ -1639,7 +1623,13 @@ void BBQJIT::emitAllocateGCArrayUninitialized(GPRReg resultGPR, TypeSignatureInd JIT_COMMENT(m_jit, "Array allocation done do initialization"); std::optional> sizeScratch; Location sizeLocation = materializeToGPR(size, sizeScratch); - Value initValue = Value::fromI64(Wasm::isRefType(elementType.unpacked()) ? JSValue::encode(jsNull()) : 0); + Value initValue; + if (elementType.unpacked().isV128()) { + // FIXME: We should have V128 Constant. + materializeVectorConstant(v128_t { }, Location::fromFPR(wasmScratchFPR)); + initValue = Value::pinned(TypeKind::V128, Location::fromFPR(wasmScratchFPR)); + } else + initValue = Value::fromI64(Wasm::isRefType(elementType.unpacked()) ? JSValue::encode(jsNull()) : 0); emitArrayGetPayload(elementType, resultGPR, scratchGPR); diff --git a/Source/JavaScriptCore/wasm/WasmFunctionParser.h b/Source/JavaScriptCore/wasm/WasmFunctionParser.h index 4f4cf92ad41f..bb18a422a6e7 100644 --- a/Source/JavaScriptCore/wasm/WasmFunctionParser.h +++ b/Source/JavaScriptCore/wasm/WasmFunctionParser.h @@ -247,7 +247,9 @@ class FunctionParser : public Parser, public FunctionParserTypes::binaryCompareCase(OpType op, BinaryOperationHandle BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get if's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few arguments on stack for if block. If expects ", argumentCount, ", but only ", sliceSize, " were present. If block has signature: ", inlineSignature); + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) - WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[parentStackHeight + i].type(), inlineSignature.argumentType(i)), "Loop expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", m_expressionStack[parentStackHeight + i].type()); auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType control; @@ -722,12 +721,9 @@ auto FunctionParser::unaryCompareCase(OpType op, UnaryOperationHandler BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get if's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few arguments on stack for if block. If expects ", argumentCount, ", but only ", sliceSize, " were present. If block has signature: ", inlineSignature); + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) - WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[parentStackHeight + i].type(), inlineSignature.argumentType(i)), "Loop expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", m_expressionStack[parentStackHeight + i].type()); auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType control; @@ -1900,22 +1896,61 @@ auto FunctionParser::checkLocalInitialized(uint32_t index) -> PartialRe } template -auto FunctionParser::checkExpressionStack(const ControlType& controlData, bool forceSignature) -> PartialResult +auto FunctionParser::checkArgumentsAndWiden(const BlockSignature& blockSignature) -> PartialResult +{ + const uint32_t argumentCount = blockSignature.argumentCount(); + const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; + WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few values on stack for block. Block expects "_s, argumentCount, ", but only "_s, sliceSize, " were present. Block has signature: "_s, blockSignature); + const uint32_t offset = m_expressionStack.size() - argumentCount; + for (unsigned i = 0; i < argumentCount; ++i) { + auto& slot = m_expressionStack[offset + i]; + const auto expectedType = blockSignature.argumentType(i); + WASM_VALIDATOR_FAIL_IF(!isSubtype(slot.type(), expectedType), "Block expects the argument at index "_s, i, " to be "_s, expectedType, " but argument has type "_s, slot.type()); + // Widen the operand to the block's declared parameter type, per the spec's + // push_ctrl(op, in, out) doing push_vals(in): the block body must be validated + // against its declared parameter types, not the narrower subtype that flowed in. + // https://webassembly.github.io/spec/core/bikeshed/#validation-of-opcode-sequences + slot.setType(expectedType); + } + + return { }; +} + +template +auto FunctionParser::checkResultsAndWiden(const BlockSignature& blockSignature) -> PartialResult { - const auto& blockSignature = controlData.signature(); const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; WASM_VALIDATOR_FAIL_IF(blockSignature.returnCount() != sliceSize, " block with type: "_s, blockSignature, " returns: "_s, blockSignature.returnCount(), " but stack has: "_s, sliceSize, " values"_s); for (unsigned i = 0; i < blockSignature.returnCount(); ++i) { - const auto actualType = m_expressionStack[m_currentStackBegin + i].type(); + auto& slot = m_expressionStack[m_currentStackBegin + i]; const auto expectedType = blockSignature.returnType(i); - WASM_VALIDATOR_FAIL_IF(!isSubtype(actualType, expectedType), "control flow returns with unexpected type. "_s, actualType, " is not a "_s, expectedType); - if (forceSignature) - m_expressionStack[m_currentStackBegin + i].setType(expectedType); + WASM_VALIDATOR_FAIL_IF(!isSubtype(slot.type(), expectedType), "control flow returns with unexpected type. "_s, slot.type(), " is not a "_s, expectedType); + // Widen the operand to the block's declared result type, per the spec's + // end doing push_vals(frame.end_types): results leave the block as the + // declared type, not the narrower subtype that reached the end. + // https://webassembly.github.io/spec/core/bikeshed/#validation-of-opcode-sequences + slot.setType(expectedType); } return { }; } +template +auto FunctionParser::endBlockAndCheckResultTypes(ControlEntry& entry) -> PartialResult +{ + // Widen each result to the block signature type before ending the block. + // FIXME: mutating the expression stack for the block result is effectful, but there's no + // better API yet. See https://bugs.webkit.org/show_bug.cgi?id=164353 + WASM_FAIL_IF_HELPER_FAILS(checkResultsAndWiden(entry.controlData.signature())); + const uint32_t parentBegin = parentEntryBegin(); + auto enclosedStack = m_expressionStack.mutableSpan().subspan(parentBegin); + // We should avoid adding other callsites of endBlock. Since a new block is a sign of a + // merge point and it would be a security bug to fail to widen the types. + WASM_TRY_ADD_TO_CONTEXT(endBlock(entry, enclosedStack)); + m_currentStackBegin = parentBegin; + return { }; +} + template auto FunctionParser::parseArrayTypeDefinition(ASCIILiteral operation, bool isNullable, TypeSignatureIndex& typeIndex, FieldType& elementType, Type& arrayRefType) -> PartialResult { @@ -3464,15 +3499,8 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get block's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few values on stack for block. Block expects ", argumentCount, ", but only ", sliceSize, " were present. Block has inlineSignature: ", inlineSignature); - const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) { - Type type = m_expressionStack[parentStackHeight + i].type(); - WASM_VALIDATOR_FAIL_IF(!isSubtype(type, inlineSignature.argumentType(i)), "Block expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", type); - } + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType block; @@ -3485,15 +3513,9 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get loop's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few values on stack for loop block. Loop expects ", argumentCount, ", but only ", sliceSize, " were present. Loop has inlineSignature: ", inlineSignature); + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) { - Type type = m_expressionStack[parentStackHeight + i].type(); - WASM_VALIDATOR_FAIL_IF(!isSubtype(type, inlineSignature.argumentType(i)), "Loop expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", type); - } auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType loop; @@ -3512,13 +3534,9 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition"_s); WASM_VALIDATOR_FAIL_IF(!condition.type().isI32(), "if condition must be i32, got ", condition.type()); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few arguments on stack for if block. If expects ", argumentCount, ", but only ", sliceSize, " were present. If block has signature: ", inlineSignature); + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) - WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[parentStackHeight + i].type(), inlineSignature.argumentType(i)), "Loop expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", m_expressionStack[parentStackHeight + i].type()); auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType control; @@ -3539,7 +3557,7 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) ControlEntry& controlEntry = m_controlStack.last(); WASM_VALIDATOR_FAIL_IF(!ControlType::isIf(controlEntry.controlData), "else block isn't associated to an if"); - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(controlEntry.controlData)); + WASM_FAIL_IF_HELPER_FAILS(checkResultsAndWiden(controlEntry.controlData.signature())); auto ifBranchResults = m_expressionStack.mutableSpan().subspan(m_currentStackBegin); WASM_TRY_ADD_TO_CONTEXT(addElse(controlEntry.controlData, ifBranchResults)); m_expressionStack.shrink(m_currentStackBegin); @@ -3553,13 +3571,9 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get try's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few arguments on stack for try block. Try expects ", argumentCount, ", but only ", sliceSize, " were present. Try block has signature: ", inlineSignature); + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) - WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[parentStackHeight + i].type(), inlineSignature.argumentType(i)), "Try expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", m_expressionStack[parentStackHeight + i].type()); auto args = m_expressionStack.mutableSpan().last(argumentCount); ControlType control; @@ -3580,7 +3594,7 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) ControlEntry& controlEntry = m_controlStack.last(); WASM_VALIDATOR_FAIL_IF(!isTryOrCatch(controlEntry.controlData), "catch block isn't associated to a try"); - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(controlEntry.controlData)); + WASM_FAIL_IF_HELPER_FAILS(checkResultsAndWiden(controlEntry.controlData.signature())); ResultList results; auto preCatchStack = m_expressionStack.mutableSpan().subspan(m_currentStackBegin); @@ -3606,7 +3620,7 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) ControlEntry& controlEntry = m_controlStack.last(); WASM_VALIDATOR_FAIL_IF(!isTryOrCatch(controlEntry.controlData), "catch block isn't associated to a try"); - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(controlEntry.controlData)); + WASM_FAIL_IF_HELPER_FAILS(checkResultsAndWiden(controlEntry.controlData.signature())); auto preCatchStack = m_expressionStack.mutableSpan().subspan(m_currentStackBegin); WASM_TRY_ADD_TO_CONTEXT(addCatchAll(preCatchStack, controlEntry.controlData)); @@ -3622,14 +3636,8 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) BlockSignature inlineSignature; WASM_PARSER_FAIL_IF(!parseBlockSignatureAndNotifySIMDUseIfNeeded(inlineSignature), "can't get try_table's signature"_s); - const uint32_t sliceSize = m_expressionStack.size() - m_currentStackBegin; const uint32_t argumentCount = inlineSignature.argumentCount(); - WASM_VALIDATOR_FAIL_IF(sliceSize < argumentCount, "Too few values on stack for block. Block expects ", argumentCount, ", but only ", sliceSize, " were present. Block has inlineSignature: ", inlineSignature); - const uint32_t parentStackHeight = m_expressionStack.size() - argumentCount; - for (unsigned i = 0; i < argumentCount; ++i) { - Type type = m_expressionStack[parentStackHeight + i].type(); - WASM_VALIDATOR_FAIL_IF(!isSubtype(type, inlineSignature.argumentType(i)), "Block expects the argument at index", i, " to be ", inlineSignature.argumentType(i), " but argument has type ", type); - } + WASM_FAIL_IF_HELPER_FAILS(checkArgumentsAndWiden(inlineSignature)); uint32_t numberOfCatches; Vector targets; @@ -3714,13 +3722,8 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) WASM_VALIDATOR_FAIL_IF(!ControlType::isTry(targetData) && !ControlType::isTopLevel(targetData), "delegate target isn't a try or the top level block"); WASM_TRY_ADD_TO_CONTEXT(addDelegate(targetData, controlEntry.controlData)); - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(controlEntry.controlData)); - - const uint32_t parentBegin = parentEntryBegin(); - auto enclosedStack = m_expressionStack.mutableSpan().subspan(parentBegin); - WASM_TRY_ADD_TO_CONTEXT(endBlock(controlEntry, enclosedStack)); - - m_currentStackBegin = parentBegin; + // Unlike the sibling catch/catch_all arms, delegate ends the try block, so it widens results. + WASM_FAIL_IF_HELPER_FAILS(endBlockAndCheckResultTypes(controlEntry)); resetLocalInitStackToHeight(controlEntry.localInitStackHeight); return { }; } @@ -3849,26 +3852,13 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) case End: { ControlEntry data = m_controlStack.takeLast(); if (ControlType::isIf(data.controlData)) { - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(data.controlData)); + WASM_FAIL_IF_HELPER_FAILS(checkResultsAndWiden(data.controlData.signature())); auto ifBranchResults = m_expressionStack.mutableSpan().subspan(m_currentStackBegin); WASM_TRY_ADD_TO_CONTEXT(addElse(data.controlData, ifBranchResults)); m_expressionStack.shrink(m_currentStackBegin); m_expressionStack.append(data.elseBlockStack.span()); } - - // FIXME: endBlock may modify the expressionStack slice for the result of the block. - // That's a little too effectful but we don't have a better API right now. - // see: https://bugs.webkit.org/show_bug.cgi?id=164353 - - // The spec requires the output type of a structured control instruction to be - // the result type from its signature, even when the fallthrough value is a subtype. - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(data.controlData, true)); - - const uint32_t parentBegin = parentEntryBegin(); - auto enclosedStack = m_expressionStack.mutableSpan().subspan(parentBegin); - WASM_TRY_ADD_TO_CONTEXT(endBlock(data, enclosedStack)); - - m_currentStackBegin = parentBegin; + WASM_FAIL_IF_HELPER_FAILS(endBlockAndCheckResultTypes(data)); if (!ControlType::isTopLevel(data.controlData)) resetLocalInitStackToHeight(data.localInitStackHeight); return { }; @@ -4064,12 +4054,7 @@ auto FunctionParser::parseUnreachableExpression() -> PartialResult WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData)); m_expressionStack.shrink(m_currentStackBegin); m_expressionStack.append(data.elseBlockStack.span()); - WASM_FAIL_IF_HELPER_FAILS(checkExpressionStack(data.controlData)); - - // Reachable End handling: the combined enclosedStack now lives in - // m_expressionStack[parentBegin..end]. - auto enclosedStack = m_expressionStack.mutableSpan().subspan(parentBegin); - WASM_TRY_ADD_TO_CONTEXT(endBlock(data, enclosedStack)); + WASM_FAIL_IF_HELPER_FAILS(endBlockAndCheckResultTypes(data)); } else { m_expressionStack.shrink(m_currentStackBegin); const auto& sig = data.controlData.signature(); diff --git a/Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp index d487c5640138..c9f887518938 100644 --- a/Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp +++ b/Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp @@ -1328,6 +1328,9 @@ OMGIRGenerator::OMGIRGenerator(AbstractHeapRepository& heaps, CompilationContext m_proc.pinRegister(GPRInfo::wasmContextInstancePointer); m_proc.pinRegister(GPRInfo::wasmBaseMemoryPointer); + // FIXME: The wasm ABI effectively has to assume this is a caller save when getting + // called by wasm, so there's no point in saving and restoring it if B3 chooses to + // use it. We actively don't restore this register in many cases anyway e.g. tail calls. if (mode == MemoryMode::BoundsChecking) m_proc.pinRegister(GPRInfo::wasmBoundsCheckingSizeRegister); @@ -1786,9 +1789,28 @@ auto OMGIRGenerator::addTableSet(unsigned tableIndex, ExpressionType index, Expr auto OMGIRGenerator::addRefFunc(FunctionSpaceIndex index, ExpressionType& result) -> PartialResult { - // FIXME: Emit this inline . - result = push(callWasmOperation(m_currentBlock, wasmRefType(), operationWasmRefFunc, - instanceValue(), constant(toB3Type(Types::I32), index))); + auto* loaded = m_currentBlock->appendNew(m_proc, Load, wasmRefType(), origin(), instanceValue(), safeCast(JSWebAssemblyInstance::offsetOfFunctionWrapper(m_info, index))); + m_heaps.decorateMemory(&m_heaps.JSWebAssemblyInstance_functionWrappers[index], loaded); + + auto* slowPath = m_proc.addBlock(); + auto* continuation = m_proc.addBlock(); + auto* phi = continuation->appendNew(m_proc, Phi, wasmRefType(), origin()); + + m_currentBlock->appendNew(m_proc, origin(), loaded, phi); + m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(), loaded, + FrequentedBlock(continuation), FrequentedBlock(slowPath, FrequencyClass::Rare)); + slowPath->addPredecessor(m_currentBlock); + continuation->addPredecessor(m_currentBlock); + + m_currentBlock = slowPath; + auto* called = callWasmOperation(m_currentBlock, wasmRefType(), operationWasmRefFunc, + instanceValue(), constant(Int32, index)); + m_currentBlock->appendNew(m_proc, origin(), called, phi); + m_currentBlock->appendNewControlValue(m_proc, Jump, origin(), continuation); + continuation->addPredecessor(m_currentBlock); + + m_currentBlock = continuation; + result = push(phi); TRACE_VALUE(Wasm::Types::Funcref, get(result), "ref_func ", index); return { }; } @@ -5822,6 +5844,11 @@ static inline void prepareForTailCallImpl(unsigned functionIndex, CCallHelpers& entries.reserveInitialCapacity(calleeSaves.registerCount() + functionSignature.argumentCount() + 1); for (const auto& regAtOffset : calleeSaves) { + // Don't restore wasmBoundsCheckingSizeRegister since we may have set it when checking for + // a cross-instance call. It's not a normal callee save independent of whether we used + // it or not. + if (regAtOffset.reg() == GPRInfo::wasmBoundsCheckingSizeRegister) + continue; ShuffleEntry entry; entry.src = ShuffleLocation::fromStack(fpOffsetToSPOffset(regAtOffset.offset())); if (regAtOffset.reg().isGPR()) { diff --git a/Source/JavaScriptCore/wasm/js/JSToWasm.cpp b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp index f1e7f0b10c65..8a020292f7e4 100644 --- a/Source/JavaScriptCore/wasm/js/JSToWasm.cpp +++ b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp @@ -600,11 +600,19 @@ CodePtr RTT::jsToWasmICEntrypoint() const slowPath.append(jit.branchPtr(CCallHelpers::NotEqual, scratchJSR.payloadGPR(), CCallHelpers::TrustedImmPtr(targetRTT.ptr()))); } + if (type.isNullable()) + isNull.link(&jit); + } else if (Wasm::isI31ref(type)) { + jit.loadValue(jsParam, scratchJSR); + auto isNull = jit.branchIfNull(scratchJSR); + if (!type.isNullable()) + slowPath.append(isNull); + slowPath.append(jit.branchIfNotInt32(scratchJSR, DoNotHaveTagRegisters)); + slowPath.append(jit.branch32(CCallHelpers::GreaterThan, scratchJSR.payloadGPR(), CCallHelpers::TrustedImm32(Wasm::maxI31ref))); + slowPath.append(jit.branch32(CCallHelpers::LessThan, scratchJSR.payloadGPR(), CCallHelpers::TrustedImm32(Wasm::minI31ref))); if (type.isNullable()) isNull.link(&jit); } else if (!Wasm::isExternref(type)) { - // FIXME: this should implement some fast paths for, e.g., i31refs and other - // types that can be easily handled. slowPath.append(jit.jump()); } diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.cpp index 47478b1a743e..f15b4205dade 100644 --- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.cpp +++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.cpp @@ -69,9 +69,9 @@ void JSWebAssemblyArray::fill(VM& vm, uint32_t offset, uint64_t value, uint32_t { // Handle ref types separately to ensure write barriers are in effect. if (elementsAreRefTypes()) { - // FIXME: We should have a GCSafeMemfill. - for (size_t i = 0; i < size; i++) - set(vm, offset + i, value); + for (size_t i = 0; i < size; ++i) + setWithoutWriteBarrier(offset + i, value); + vm.writeBarrier(this); return; } diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.h index 172f8056b516..0e20af09f7ae 100644 --- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.h +++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.h @@ -132,6 +132,7 @@ class JSWebAssemblyArray final : public WebAssemblyGCObjectBase { private: friend class LLIntOffsetsExtractor; + inline void setWithoutWriteBarrier(uint32_t index, uint64_t value); inline std::span bytes(); // NB: It's *HIGHLY* recommended that you don't use these directly since you'll have to remember to clean up the alignment for v128. diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.h index bc50a2469ba8..27e06128f567 100644 --- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.h +++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.h @@ -142,15 +142,20 @@ v128_t JSWebAssemblyArray::getVector(uint32_t index) return span()[index]; } -void JSWebAssemblyArray::set(VM& vm, uint32_t index, uint64_t value) +void JSWebAssemblyArray::setWithoutWriteBarrier(uint32_t index, uint64_t value) { visitSpanNonVector([&](std::span span) ALWAYS_INLINE_LAMBDA { span[index] = static_cast(value); - if (elementsAreRefTypes()) - vm.writeBarrier(this); }); } +void JSWebAssemblyArray::set(VM& vm, uint32_t index, uint64_t value) +{ + setWithoutWriteBarrier(index, value); + if (elementsAreRefTypes()) + vm.writeBarrier(this); +} + void JSWebAssemblyArray::set(VM&, uint32_t index, v128_t value) { ASSERT(elementType().type.as().kind() == Wasm::TypeKind::V128); diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp index a4591d7f54c9..2f3cf559ce37 100644 --- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp +++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp @@ -136,6 +136,7 @@ JSWebAssemblyInstance::JSWebAssemblyInstance(VM& vm, Structure* structure, JSWeb } memset(reinterpret_cast(baselineDatas().data()), 0, baselineDatas().size_bytes()); + zeroSpan(asMutableByteSpan(functionWrappers())); if (m_moduleInformation->hasGCObjectTypes()) { memset(reinterpret_cast(gcObjectStructureIDs().data()), 0, gcObjectStructureIDs().size_bytes()); CompleteSubspace* subspace = JSWebAssemblyArray::subspaceFor(vm); @@ -222,9 +223,9 @@ void JSWebAssemblyInstance::visitChildrenImpl(JSCell* cell, Visitor& visitor) visitor.append(thisObject->gcObjectStructureID(i)); } - Locker locker { cell->cellLock() }; for (auto& wrapper : thisObject->functionWrappers()) - visitor.appendUnbarriered(wrapper.get()); + visitor.append(wrapper); + Locker locker { cell->cellLock() }; for (auto& entry : thisObject->m_constantExpressionValues) visitor.append(entry.value); for (auto& entry : thisObject->m_tagWrappers) @@ -308,9 +309,7 @@ Identifier JSWebAssemblyInstance::createPrivateModuleKey() size_t JSWebAssemblyInstance::allocationSize(const Wasm::ModuleInformation& info) { - if (info.hasGCObjectTypes()) - return offsetOfAllocatorForGCObject(info, MarkedSpace::numSizeClasses); - return offsetOfBaselineData(info, info.internalFunctionCount()); + return offsetOfFunctionWrapper(info, info.functionIndexSpaceSize()); } @@ -349,14 +348,33 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::tryCreate(VM& vm, Structure* insta return exception(createTypeError(globalObject, "can't make WebAssembly.Instance because there is no imports Object and the WebAssembly.Module requires imports"_s)); } + auto isReservedESMName = [](const Wasm::Name& name) { + return startsWith(name.span(), "wasm:"_s) || startsWith(name.span(), "wasm-js:"_s); + }; + + if (creationMode == CreationMode::FromModuleLoader) { + for (auto& exp : moduleInformation.exports) { + if (isReservedESMName(exp.field)) + return exception(createJSWebAssemblyLinkError(globalObject, vm, makeString("Export name '"_s, makeString(exp.field), "' is reserved"_s))); + } + } + // For each import i in module.imports: { IdentifierSet specifiers; for (auto& import : moduleInformation.imports) { auto moduleName = Identifier::fromString(vm, makeAtomString(import.module)); auto fieldName = Identifier::fromString(vm, makeAtomString(import.field)); + if (creationMode == CreationMode::FromModuleLoader) { + if (isReservedESMName(import.field)) + return exception(createJSWebAssemblyLinkError(globalObject, vm, makeString("Import name '"_s, StringView(fieldName.impl()), "' is reserved"_s))); + if (startsWith(import.module.span(), "wasm-js:"_s)) + return exception(createJSWebAssemblyLinkError(globalObject, vm, makeString("Import module '"_s, StringView(moduleName.impl()), "' is reserved"_s))); + } + bool skipRequestedModule = creationMode == CreationMode::FromModuleLoader + && (moduleInformation.importedStringConstantsEquals(import.module) || moduleInformation.builtinSetsInclude(import.module)); auto result = specifiers.add(moduleName.impl()); - if (result.isNewEntry) + if (result.isNewEntry && !skipRequestedModule) moduleRecord->appendRequestedModule(moduleName, nullptr); moduleRecord->addImportEntry(WebAssemblyModuleRecord::ImportEntry { WebAssemblyModuleRecord::ImportEntryType::Single, @@ -445,18 +463,17 @@ void JSWebAssemblyInstance::setGlobal(unsigned i, JSValue value) JSValue JSWebAssemblyInstance::getFunctionWrapper(unsigned i) const { - JSValue value = m_functionWrappers.get(i).get(); - if (value.isEmpty()) - return jsNull(); - return value; + ASSERT(i < functionWrappers().size()); + JSValue value = functionWrappers()[i].get(); + return value ? value : jsNull(); } void JSWebAssemblyInstance::setFunctionWrapper(unsigned i, JSValue value) { + ASSERT(i < functionWrappers().size()); ASSERT(value.isCallable()); - ASSERT(!m_functionWrappers.contains(i)); - Locker locker { cellLock() }; - m_functionWrappers.set(i, WriteBarrier(vm(), this, value)); + ASSERT(!functionWrappers()[i].get()); + functionWrappers()[i].set(vm(), this, value); ASSERT(getFunctionWrapper(i) == value); } diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h index 604bad2ebc1a..dcb05769d5e1 100644 --- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h +++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h @@ -73,7 +73,7 @@ class BaselineData; } // The layout of a JSWebAssemblyInstance is -// { struct JSWebAssemblyInstance }[ WasmMemoryBaseAndSize ][ WasmOrJSImportableFunctionCallLinkInfo ][ Wasm::Table* ][ Global::Value ][ Wasm::BaselineData* ][ WebAssemblyGCStructure* ][ Allocator* ] +// { struct JSWebAssemblyInstance }[ WasmMemoryBaseAndSize ][ WasmOrJSImportableFunctionCallLinkInfo ][ Wasm::Table* ][ Global::Value ][ Wasm::BaselineData* ][ WebAssemblyGCStructure* ][ Allocator* ][ WriteBarrier function wrappers ] // in a compound TrailingArray-like format. class JSWebAssemblyInstance final : public JSNonFinalObject { friend class LLIntOffsetsExtractor; @@ -182,8 +182,6 @@ class JSWebAssemblyInstance final : public JSNonFinalObject { static constexpr ptrdiff_t offsetOfVM() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_vm); } static constexpr ptrdiff_t offsetOfModuleRecord() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_moduleRecord); } - using FunctionWrapperMap = UncheckedKeyHashMap, IntHash, WTF::UnsignedWithZeroKeyHashTraits>; - static constexpr ptrdiff_t offsetOfSoftStackLimit() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_stackMirror) + StackManager::Mirror::offsetOfSoftStackLimit(); } Wasm::Module& module() const { return m_module.get(); } @@ -308,7 +306,6 @@ class JSWebAssemblyInstance final : public JSNonFinalObject { const BitVector& globalsToMark() LIFETIME_BOUND { return m_globalsToMark; } const BitVector& globalsToBinding() LIFETIME_BOUND { return m_globalsToBinding; } JSValue getFunctionWrapper(unsigned) const; - typename FunctionWrapperMap::ValuesConstIteratorRange functionWrappers() const { return m_functionWrappers.values(); } void setFunctionWrapper(unsigned, JSValue); JSValue ensureFunctionWrapper(Wasm::FunctionSpaceIndex); void setBuiltinCalleeBits(uint32_t builtinID, CalleeBits calleeBits) { m_builtinCalleeBits[builtinID] = calleeBits; } @@ -378,6 +375,14 @@ class JSWebAssemblyInstance final : public JSNonFinalObject { return roundUpToMultipleOf(offsetOfGCObjectStructureID(info, info.typeCount())) + sizeof(Allocator) * index; } + static ptrdiff_t offsetOfFunctionWrapper(const Wasm::ModuleInformation& info, unsigned index) + { + ptrdiff_t base = info.hasGCObjectTypes() + ? offsetOfAllocatorForGCObject(info, MarkedSpace::numSizeClasses) + : offsetOfBaselineData(info, info.internalFunctionCount()); + return roundUpToMultipleOf)>(base) + sizeof(WriteBarrier) * index; + } + static size_t offsetOfTargetInstance(const Wasm::ModuleInformation& info, size_t importFunctionNum) { return offsetOfImportFunctionInfo(info, importFunctionNum) + OBJECT_OFFSETOF(Wasm::WasmOrJSImportableFunctionCallLinkInfo, targetInstance); } static size_t offsetOfEntrypointLoadLocation(const Wasm::ModuleInformation& info, size_t importFunctionNum) { return offsetOfImportFunctionInfo(info, importFunctionNum) + OBJECT_OFFSETOF(Wasm::WasmOrJSImportableFunctionCallLinkInfo, entrypointLoadLocation); } static size_t offsetOfBoxedCallee(const Wasm::ModuleInformation& info, size_t importFunctionNum) { return offsetOfImportFunctionInfo(info, importFunctionNum) + OBJECT_OFFSETOF(Wasm::WasmOrJSImportableFunctionCallLinkInfo, boxedCallee); } @@ -420,6 +425,16 @@ class JSWebAssemblyInstance final : public JSNonFinalObject { return unsafeMakeSpan(std::bit_cast(std::bit_cast(this) + offsetOfAllocatorForGCObject(m_moduleInformation, 0)), MarkedSpace::numSizeClasses); } + std::span> functionWrappers() + { + return std::span { std::bit_cast*>(std::bit_cast(this) + offsetOfFunctionWrapper(m_moduleInformation, 0)), m_moduleInformation->functionIndexSpaceSize() }; + } + + std::span> functionWrappers() const + { + return std::span { std::bit_cast*>(std::bit_cast(this) + offsetOfFunctionWrapper(m_moduleInformation, 0)), m_moduleInformation->functionIndexSpaceSize() }; + } + unsigned numImportFunctions() const { return m_numImportFunctions; } WasmOrJSImportableFunctionCallLinkInfo* importFunctionInfo(size_t importFunctionNum) { @@ -485,7 +500,6 @@ class JSWebAssemblyInstance final : public JSNonFinalObject { RefPtr m_wasmMemory; Wasm::Global::Value* m_globals { nullptr }; - FunctionWrapperMap m_functionWrappers; using ConstantExpressionValueMap = UncheckedKeyHashMap, IntHash, WTF::UnsignedWithZeroKeyHashTraits>; ConstantExpressionValueMap m_constantExpressionValues; diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp index 72f16569fe84..28f11fb4c159 100644 --- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp +++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp @@ -46,6 +46,7 @@ #include "WebAssemblyModulePrototype.h" #include #include +#include namespace JSC { static JSC_DECLARE_HOST_FUNCTION(webAssemblyModuleCustomSections); @@ -89,8 +90,7 @@ JSC_DEFINE_HOST_FUNCTION(webAssemblyModuleCustomSections, (JSGlobalObject* globa const auto& customSections = module->moduleInformation().customSections; for (const Wasm::CustomSection& section : customSections) { - // FIXME: Add a function that compares a String with a span so we don't need to make a string. - if (WTF::makeString(section.name) == sectionNameString) { + if (equal(sectionNameString, section.name.span())) { auto buffer = ArrayBuffer::tryCreate(section.payload.span()); if (!buffer) return JSValue::encode(throwException(globalObject, throwScope, createOutOfMemoryError(globalObject))); diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp index 8b1c8e0f22e8..1abac82e44bb 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp @@ -1,6 +1,8 @@ +__ZN6webrtc10I010Buffer6CreateEii __ZN6webrtc10I420Buffer12MutableDataUEv __ZN6webrtc10I420Buffer12MutableDataVEv __ZN6webrtc10I420Buffer12MutableDataYEv +__ZN6webrtc10I420Buffer6CreateEii __ZN6webrtc10I420Buffer6RotateERKNS_19I420BufferInterfaceENS_13VideoRotationE __ZN6webrtc10I420Buffer8SetBlackEPS0_ __ZN6webrtc10VideoFrameD1Ev @@ -426,3 +428,6 @@ __ZNK6webrtc18VideoFrameMetadata15GetDependenciesEv __ZNK6webrtc8RtpCodec9mime_typeEv __ZN6webrtc14SdpVideoFormatC1ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERKNS_17CodecParameterMapE __ZN4absl19ThrowStdLengthErrorEPKc +__ZN6webrtc10I010Buffer12MutableDataUEv +__ZN6webrtc10I010Buffer12MutableDataVEv +__ZN6webrtc10I010Buffer12MutableDataYEv diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig index 364eae747465..417e25c009a7 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig @@ -90,6 +90,6 @@ OTHER_LDFLAGS = $(inherited) $(SOURCE_VERSION_LDFLAGS) $(WEBRTC_LDFLAGS_ENABLE_L // Allow fuzzers to link to libwebrtc.dylib. WEBRTC_ALLOWABLE_CLIENTS = $(WEBRTC_ALLOWABLE_CLIENTS_$(WK_NOT_$(ENABLE_LIBFUZZER))); -WEBRTC_ALLOWABLE_CLIENTS_YES = -allowable_client WebCore -allowable_client WebCoreTestSupport -allowable_client WebKit; +WEBRTC_ALLOWABLE_CLIENTS_YES = -allowable_client WebCore -allowable_client WebCoreTestSupport -allowable_client WebKit -allowable_client TestWebKitAPI; WARNING_CFLAGS = $(inherited) -Wno-nullability-completeness; diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/webkit_sdk/WebKit/WebKitUtilities.mm b/Source/ThirdParty/libwebrtc/Source/webrtc/webkit_sdk/WebKit/WebKitUtilities.mm index f5631db00b03..d5342a5ad11b 100644 --- a/Source/ThirdParty/libwebrtc/Source/webrtc/webkit_sdk/WebKit/WebKitUtilities.mm +++ b/Source/ThirdParty/libwebrtc/Source/webrtc/webkit_sdk/WebKit/WebKitUtilities.mm @@ -436,7 +436,7 @@ bool copyVideoFrameBuffer(VideoFrameBuffer& buffer, uint8_t* data) auto* i420Frame = buffer.GetI420(); auto* dataY = data; auto strideY = i420Frame->width(); - auto strideUV = i420Frame->width(); + auto strideUV = i420Frame->width() & 1 ? i420Frame->width() + 1 : i420Frame->width(); auto* dataUV = data + (i420Frame->width() * i420Frame->height()); return !libyuv::I420ToNV12(i420Frame->DataY(), i420Frame->StrideY(), i420Frame->DataU(), i420Frame->StrideU(), @@ -448,7 +448,7 @@ bool copyVideoFrameBuffer(VideoFrameBuffer& buffer, uint8_t* data) auto* i010Frame = buffer.GetI010(); auto* dataY = reinterpret_cast(data); auto strideY = i010Frame->width(); - auto strideUV = i010Frame->width(); + auto strideUV = i010Frame->width() & 1 ? i010Frame->width() + 1 : i010Frame->width(); auto* dataUV = dataY + (i010Frame->width() * i010Frame->height()); return !libyuv::I010ToP010(i010Frame->DataY(), i010Frame->StrideY(), i010Frame->DataU(), i010Frame->StrideU(), diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index 679c0a30ed5c..fbe0592acd6d 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -10364,18 +10364,18 @@ WebExtensionBookmarksEnabled: WebExtensionOffscreenEnabled: type: bool - status: testable + status: stable category: extensions humanReadableName: "WebExtension Offscreen API" humanReadableDescription: "Enable support for WebExtensions using the Offscreen API" condition: ENABLE(WK_WEB_EXTENSIONS_OFFSCREEN) defaultValue: WebKitLegacy: - default: false + default: true WebKit: - default: false + default: true WebCore: - default: false + default: true WebExtensionSidebarEnabled: type: bool diff --git a/Source/WTF/wtf/CMakeLists.txt b/Source/WTF/wtf/CMakeLists.txt index 239a26355298..d21bf31baf81 100644 --- a/Source/WTF/wtf/CMakeLists.txt +++ b/Source/WTF/wtf/CMakeLists.txt @@ -803,6 +803,7 @@ elseif (APPLE) elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") list(APPEND WTF_PUBLIC_HEADERS linux/CurrentProcessMemoryStatus.h + linux/HighPriorityThreads.h linux/ProcessMemoryFootprint.h ) endif () diff --git a/Source/WTF/wtf/NeverDestroyed.h b/Source/WTF/wtf/NeverDestroyed.h index 974eee494e3c..f6cbe8eb9fb2 100644 --- a/Source/WTF/wtf/NeverDestroyed.h +++ b/Source/WTF/wtf/NeverDestroyed.h @@ -72,13 +72,13 @@ template class NeverDestroyed { template NeverDestroyed(Args&&... args) { AccessTraits::assertAccess(); - MaybeRelax(new (storagePointer()) T(std::forward(args)...)); + new (storagePointer()) T(std::forward(args)...); } NeverDestroyed(NeverDestroyed&& other) { AccessTraits::assertAccess(); - MaybeRelax(new (storagePointer()) T(WTF::move(*other.storagePointer()))); + new (storagePointer()) T(WTF::move(*other.storagePointer())); } operator T&() { return *storagePointer(); } @@ -100,13 +100,6 @@ template class NeverDestroyed { return const_cast(m_storage.get()); } - template::value> struct MaybeRelax { - explicit MaybeRelax(PtrType*) { } - }; - template struct MaybeRelax { - explicit MaybeRelax(PtrType* ptr) { ptr->relaxAdoptionRequirement(); } - }; - // FIXME: Investigate whether we should allocate a hunk of virtual memory // and hand out chunks of it to NeverDestroyed instead, to reduce fragmentation. AlignedStorage m_storage; @@ -135,7 +128,7 @@ template class LazyNeverDestroyed { #if ASSERT_ENABLED m_isConstructed = true; #endif - MaybeRelax(new (storagePointerWithoutAccessCheck()) T(std::forward(args)...)); + new (storagePointerWithoutAccessCheck()) T(std::forward(args)...); } operator T&() { return *storagePointer(); } @@ -167,13 +160,6 @@ template class LazyNeverDestroyed { return storagePointerWithoutAccessCheck(); } - template::value> struct MaybeRelax { - explicit MaybeRelax(PtrType*) { } - }; - template struct MaybeRelax { - explicit MaybeRelax(PtrType* ptr) { ptr->relaxAdoptionRequirement(); } - }; - #if ASSERT_ENABLED // LazyNeverDestroyed objects are always static, so this variable is initialized to false. // It must not be initialized dynamically; that would not be thread safe. diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h index 4d71a85c4cff..972895c156e8 100644 --- a/Source/WTF/wtf/PlatformEnableCocoa.h +++ b/Source/WTF/wtf/PlatformEnableCocoa.h @@ -1087,7 +1087,7 @@ #endif #if !defined(ENABLE_WK_WEB_EXTENSIONS_OFFSCREEN) -#define ENABLE_WK_WEB_EXTENSIONS_OFFSCREEN 0 && ENABLE_WK_WEB_EXTENSIONS +#define ENABLE_WK_WEB_EXTENSIONS_OFFSCREEN ENABLE_WK_WEB_EXTENSIONS #endif #if !defined(ENABLE_WK_WEB_EXTENSIONS_BOOKMARKS) diff --git a/Source/WTF/wtf/Ref.h b/Source/WTF/wtf/Ref.h index 4af39c1cd381..3d2555e1e5c2 100644 --- a/Source/WTF/wtf/Ref.h +++ b/Source/WTF/wtf/Ref.h @@ -43,8 +43,6 @@ extern "C" int __asan_address_is_poisoned(void const volatile *addr); namespace WTF { -inline void adopted(const void*) { } - template struct DefaultRefDerefTraits { static constexpr bool isDefaultImplementation = true; @@ -353,7 +351,6 @@ struct IsSmartPtr> { template inline Ref adoptRef(T& reference) { - adopted(&reference); return Ref(reference, Ref::Adopt); } diff --git a/Source/WTF/wtf/RefCountDebugger.h b/Source/WTF/wtf/RefCountDebugger.h index 5361ef3086a3..7462deffbd8f 100644 --- a/Source/WTF/wtf/RefCountDebugger.h +++ b/Source/WTF/wtf/RefCountDebugger.h @@ -63,7 +63,6 @@ class RefCountDebuggerImpl : public RefCountDebuggerBase { ~RefCountDebuggerImpl() { ASSERT(m_deletionHasBegun); - ASSERT(!m_adoptionIsRequired); } #else ~RefCountDebuggerImpl() = default; @@ -73,25 +72,6 @@ class RefCountDebuggerImpl : public RefCountDebuggerBase { { applyRefDerefThreadingCheck(refCount); applyRefDuringDestructionCheck(); - -#if CHECK_REF_COUNTED_LIFECYCLE - ASSERT(!m_adoptionIsRequired); -#endif - } - - void adopted() - { -#if CHECK_REF_COUNTED_LIFECYCLE - m_adoptionIsRequired = false; -#endif - } - - void relaxAdoptionRequirement() - { -#if CHECK_REF_COUNTED_LIFECYCLE - ASSERT(m_adoptionIsRequired); - m_adoptionIsRequired = false; -#endif } // Unsafe precondition: The caller must ensure thread-safe access to this object, @@ -155,10 +135,6 @@ class RefCountDebuggerImpl : public RefCountDebuggerBase { { applyRefDerefThreadingCheck(refCount); -#if CHECK_REF_COUNTED_LIFECYCLE - ASSERT(!m_adoptionIsRequired); -#endif - ASSERT(refCount); } @@ -185,7 +161,6 @@ class RefCountDebuggerImpl : public RefCountDebuggerBase { #endif #if CHECK_REF_COUNTED_LIFECYCLE mutable std::atomic m_deletionHasBegun { false }; - mutable bool m_adoptionIsRequired { true }; #endif }; diff --git a/Source/WTF/wtf/RefCounted.h b/Source/WTF/wtf/RefCounted.h index 1633fa28e661..d5463a57c549 100644 --- a/Source/WTF/wtf/RefCounted.h +++ b/Source/WTF/wtf/RefCounted.h @@ -39,8 +39,6 @@ class RefCountedBase { uint32_t refCount() const { return m_refCount; } // Debug APIs - void adopted() { m_refCountDebugger.adopted(); } - void relaxAdoptionRequirement() { m_refCountDebugger.relaxAdoptionRequirement(); } void disableThreadingChecks() { m_refCountDebugger.disableThreadingChecks(); } RefCountDebugger& refCountDebugger() LIFETIME_BOUND { return m_refCountDebugger; } @@ -88,13 +86,6 @@ template class RefCounted : public RefCountedBase { ~RefCounted() = default; } SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT; -inline void adopted(RefCountedBase* object) -{ - if (!object) - return; - object->adopted(); -} - } // namespace WTF using WTF::RefCounted; diff --git a/Source/WTF/wtf/RefCountedWithInlineWeakPtr.h b/Source/WTF/wtf/RefCountedWithInlineWeakPtr.h index 8d14e42792d1..e35ff79d8886 100644 --- a/Source/WTF/wtf/RefCountedWithInlineWeakPtr.h +++ b/Source/WTF/wtf/RefCountedWithInlineWeakPtr.h @@ -193,16 +193,6 @@ template class RefCountedWithInlineWeakPtr { RefCountHeader& header() const { return refCountHeader(object()); } } SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT; -template - requires requires { typename U::RefCountedType; } -inline void adopted(U* object) -{ - if (!object) - return; - using T = typename U::RefCountedType; - refCountHeader(static_cast(object)).refCountDebugger().adopted(); -} - template Ref createRefCountedWithInlineWeakPtr(Args&&... args) { diff --git a/Source/WTF/wtf/RefPtr.h b/Source/WTF/wtf/RefPtr.h index 8523fbeab63c..33316d112f6d 100644 --- a/Source/WTF/wtf/RefPtr.h +++ b/Source/WTF/wtf/RefPtr.h @@ -265,7 +265,6 @@ inline bool operator==(const RefPtr& a, X* b) template inline RefPtr adoptRef(T* p) { - adopted(p); return RefPtr(p, RefPtr::Adopt); } diff --git a/Source/WTF/wtf/ThreadSafeRefCounted.h b/Source/WTF/wtf/ThreadSafeRefCounted.h index 71e7c4573e07..9426a1b4ea1a 100644 --- a/Source/WTF/wtf/ThreadSafeRefCounted.h +++ b/Source/WTF/wtf/ThreadSafeRefCounted.h @@ -48,18 +48,11 @@ class WTF_EMPTY_BASE_CLASS ThreadSafeRefCountedBase { uint32_t refCount() const { return m_refCount.load(std::memory_order_relaxed); } // Debug APIs - void adopted() { m_refCountDebugger.adopted(); } - void relaxAdoptionRequirement() { m_refCountDebugger.relaxAdoptionRequirement(); } void disableThreadingChecks() { m_refCountDebugger.disableThreadingChecks(); } ThreadSafeRefCountDebugger& refCountDebugger() LIFETIME_BOUND { return m_refCountDebugger; } protected: - ThreadSafeRefCountedBase() - { - // FIXME: Lots of subclasses violate our adoption requirements. Migrate - // this call into only those subclasses that need it. - m_refCountDebugger.relaxAdoptionRequirement(); - } + ThreadSafeRefCountedBase() = default; ~ThreadSafeRefCountedBase() { @@ -114,13 +107,6 @@ template ~ThreadSafeRefCounted() = default; } SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT; -inline void adopted(ThreadSafeRefCountedBase* object) -{ - if (!object) - return; - object->adopted(); -} - } // namespace WTF using WTF::ThreadSafeRefCounted; diff --git a/Source/WTF/wtf/ThreadSafeRefCountedWithSuppressingSaferCPPChecking.h b/Source/WTF/wtf/ThreadSafeRefCountedWithSuppressingSaferCPPChecking.h index e8a34cc5381f..95fd440d778f 100644 --- a/Source/WTF/wtf/ThreadSafeRefCountedWithSuppressingSaferCPPChecking.h +++ b/Source/WTF/wtf/ThreadSafeRefCountedWithSuppressingSaferCPPChecking.h @@ -50,18 +50,11 @@ class WTF_EMPTY_BASE_CLASS ThreadSafeRefCountedWithSuppressingSaferCPPCheckingBa uint32_t refCount() const { return m_refCount.load(std::memory_order_relaxed); } // Debug APIs - void adopted() { m_refCountDebugger.adopted(); } - void relaxAdoptionRequirement() { m_refCountDebugger.relaxAdoptionRequirement(); } void disableThreadingChecks() { m_refCountDebugger.disableThreadingChecks(); } ThreadSafeRefCountDebugger& refCountDebugger() LIFETIME_BOUND { return m_refCountDebugger; } protected: - ThreadSafeRefCountedWithSuppressingSaferCPPCheckingBase() - { - // FIXME: Lots of subclasses violate our adoption requirements. Migrate - // this call into only those subclasses that need it. - m_refCountDebugger.relaxAdoptionRequirement(); - } + ThreadSafeRefCountedWithSuppressingSaferCPPCheckingBase() = default; ~ThreadSafeRefCountedWithSuppressingSaferCPPCheckingBase() { @@ -114,13 +107,6 @@ template } } SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT; -inline void adopted(ThreadSafeRefCountedWithSuppressingSaferCPPCheckingBase* object) -{ - if (!object) - return; - object->adopted(); -} - } // namespace WTF using WTF::ThreadSafeRefCountedWithSuppressingSaferCPPChecking; diff --git a/Source/WTF/wtf/ThreadSafeWeakPtr.h b/Source/WTF/wtf/ThreadSafeWeakPtr.h index a97c97c2fdb3..b31935fd0348 100644 --- a/Source/WTF/wtf/ThreadSafeWeakPtr.h +++ b/Source/WTF/wtf/ThreadSafeWeakPtr.h @@ -52,7 +52,8 @@ class ThreadSafeWeakPtrControlBlock { return this; } - void weakDeref() + // Deleting ThreadSafeWeakPtrControlBlock does not delete a user object. + SUPPRESS_NODELETE void NODELETE weakDeref() { bool shouldDeleteControlBlock { false }; { @@ -394,7 +395,8 @@ class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr { protected: ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr() = default; - ThreadSafeWeakPtrControlBlock& controlBlock() const + // Creating & destroying ThreadSafeWeakPtrControlBlock does not delete an user object. + SUPPRESS_NODELETE ThreadSafeWeakPtrControlBlock& NODELETE controlBlock() const { // If we ever decided there was a lot of contention here we could have some lock bits in m_bits but // that seems unlikely since this is a one-way street. Once we add a controlBlock we don't go back diff --git a/Source/WTF/wtf/UniquelyOwnedPtr.h b/Source/WTF/wtf/UniquelyOwnedPtr.h index b4fcf6f82300..d224ffecd12f 100644 --- a/Source/WTF/wtf/UniquelyOwnedPtr.h +++ b/Source/WTF/wtf/UniquelyOwnedPtr.h @@ -43,7 +43,6 @@ UniquelyOwnedPtr makeUniquelyOwned(Args&&... args) { using T = typename U::RefCountedType; auto* object = RefCountedWithInlineWeakPtr::template create(std::forward(args)...); - adopted(object); return UniquelyOwnedPtr(object); } diff --git a/Source/WTF/wtf/cocoa/WorkQueueCocoa.cpp b/Source/WTF/wtf/cocoa/WorkQueueCocoa.cpp index 2c08b5a44558..486e46022034 100644 --- a/Source/WTF/wtf/cocoa/WorkQueueCocoa.cpp +++ b/Source/WTF/wtf/cocoa/WorkQueueCocoa.cpp @@ -82,7 +82,7 @@ WorkQueueBase::WorkQueueBase(OSObjectPtr&& dispatchQueue) void WorkQueueBase::platformInitialize(ASCIILiteral name, Type type, QOS qos) { - dispatch_queue_attr_t attr = type == Type::Concurrent ? DISPATCH_QUEUE_CONCURRENT : DISPATCH_QUEUE_SERIAL; + dispatch_queue_attr_t attr = type == Type::Concurrent ? concurrentQueueWithAutoreleasePoolAttrSingleton() : serialQueueWithAutoreleasePoolAttrSingleton(); attr = dispatch_queue_attr_make_with_qos_class(attr, Thread::dispatchQOSClass(qos), 0); // FIXME: This is a false positive. rdar://160931336 SUPPRESS_RETAINPTR_CTOR_ADOPT lazyInitialize(m_dispatchQueue, adoptOSObject(dispatch_queue_create(name, attr))); diff --git a/Source/WTF/wtf/darwin/DispatchExtras.h b/Source/WTF/wtf/darwin/DispatchExtras.h index dfac7c6d6671..07f4e7e2aa29 100644 --- a/Source/WTF/wtf/darwin/DispatchExtras.h +++ b/Source/WTF/wtf/darwin/DispatchExtras.h @@ -39,7 +39,19 @@ inline dispatch_queue_main_t mainDispatchQueueSingleton() return dispatch_get_main_queue(); // NOLINT } +inline dispatch_queue_attr_t serialQueueWithAutoreleasePoolAttrSingleton() +{ + return DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL; // NOLINT +} + +inline dispatch_queue_attr_t concurrentQueueWithAutoreleasePoolAttrSingleton() +{ + return DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL; // NOLINT +} + } // namespace WTF +using WTF::concurrentQueueWithAutoreleasePoolAttrSingleton; using WTF::globalDispatchQueueSingleton; using WTF::mainDispatchQueueSingleton; +using WTF::serialQueueWithAutoreleasePoolAttrSingleton; diff --git a/Source/WTF/wtf/glib/SocketConnection.cpp b/Source/WTF/wtf/glib/SocketConnection.cpp index dc3e7091b8d2..345b6668096c 100644 --- a/Source/WTF/wtf/glib/SocketConnection.cpp +++ b/Source/WTF/wtf/glib/SocketConnection.cpp @@ -39,8 +39,6 @@ SocketConnection::SocketConnection(GRefPtr&& connection, cons , m_messageHandlers(messageHandlers) , m_userData(userData) { - relaxAdoptionRequirement(); - m_readBuffer.reserveInitialCapacity(defaultBufferSize); m_writeBuffer.reserveInitialCapacity(defaultBufferSize); diff --git a/Source/WTF/wtf/linux/HighPriorityThreads.cpp b/Source/WTF/wtf/linux/HighPriorityThreads.cpp index fecd6728781a..d529d2f0d2c2 100644 --- a/Source/WTF/wtf/linux/HighPriorityThreads.cpp +++ b/Source/WTF/wtf/linux/HighPriorityThreads.cpp @@ -42,7 +42,7 @@ namespace WTF { // Requested nice value. rtkit clamps this to its own MinNiceLevel. -static constexpr int s_highPriorityNiceLevel = -20; +[[maybe_unused]] static constexpr int s_highPriorityNiceLevel = -20; HighPriorityThreads& HighPriorityThreads::singleton() { diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake index c698f21f331c..98b48cc1450d 100644 --- a/Source/WebCore/Headers.cmake +++ b/Source/WebCore/Headers.cmake @@ -2026,6 +2026,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS page/FrameConsoleClient.h page/FrameDestructionObserver.h page/FrameDestructionObserverInlines.h + page/FrameGeometrySyncData.h page/FrameIdentifier.h page/FrameInlines.h page/FrameSnapshotting.h @@ -2081,7 +2082,6 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS page/PrewarmInformation.h page/PrintContext.h page/ProcessWarming.h - page/QuirkMatch.h page/QuirkNames.h page/QuirkTable.h page/Quirks.h @@ -2117,6 +2117,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS page/TextAnimationTypes.h page/TextDirectionSubmenuInclusionBehavior.h page/TextIndicator.h + page/URLMatch.h page/TranslationContextMenuInfo.h page/UADataValues.h page/UALowEntropyJSON.h @@ -2684,6 +2685,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/PlatformTextTrack.h platform/graphics/PlatformTimeRanges.h platform/graphics/PlatformTrackConfiguration.h + platform/graphics/PlatformVideoChromaLocation.h platform/graphics/PlatformVideoColorPrimaries.h platform/graphics/PlatformVideoColorSpace.h platform/graphics/PlatformVideoMatrixCoefficients.h @@ -3438,6 +3440,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS style/values/overflow/StyleOverflowClipMargin.h style/values/overflow/StyleScrollBehavior.h style/values/overflow/StyleScrollbarGutter.h + style/values/overflow/StyleTextOverflow.h style/values/page/StylePageSize.h diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp index f91bb78204d5..cd9a3d954e42 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp @@ -93,7 +93,6 @@ MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, Refmuted()) , m_isCaptureTrack(is(context) && m_private->isCaptureTrack()) { - relaxAdoptionRequirement(); ALWAYS_LOG(LOGIDENTIFIER); m_private->addObserver(*this); diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp index 0d1b18518e85..aba3bb1ea99f 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp @@ -130,7 +130,6 @@ RTCPeerConnection::RTCPeerConnection(Document& document) #endif { ALWAYS_LOG(LOGIDENTIFIER); - relaxAdoptionRequirement(); } RTCPeerConnection::~RTCPeerConnection() diff --git a/Source/WebCore/Modules/notifications/NotificationResourcesLoader.cpp b/Source/WebCore/Modules/notifications/NotificationResourcesLoader.cpp index c56a75a99c5d..1d02de7ffe61 100644 --- a/Source/WebCore/Modules/notifications/NotificationResourcesLoader.cpp +++ b/Source/WebCore/Modules/notifications/NotificationResourcesLoader.cpp @@ -139,8 +139,6 @@ auto NotificationResourcesLoader::ResourceLoader::create(ScriptExecutionContext& NotificationResourcesLoader::ResourceLoader::ResourceLoader(ScriptExecutionContext& context, const URL& url, CompletionHandler&&)>&& completionHandler) : m_completionHandler(WTF::move(completionHandler)) { - relaxAdoptionRequirement(); - ThreadableLoaderOptions options; options.mode = FetchOptions::Mode::Cors; options.sendLoadCallbacks = SendCallbackPolicy::SendCallbacks; diff --git a/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrame.cpp b/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrame.cpp index a635371e5dc0..eaec35155b48 100644 --- a/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrame.cpp +++ b/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrame.cpp @@ -263,7 +263,7 @@ ExceptionOr> WebCodecsVideoFrame::create(ScriptExecutio if (!pixelBuffer) return Exception { ExceptionCode::InvalidStateError, "Buffer has no frame"_s }; - auto videoFrame = VideoFrame::createFromPixelBuffer(pixelBuffer.releaseNonNull(), { PlatformVideoColorPrimaries::Bt709, PlatformVideoTransferCharacteristics::Iec6196621, PlatformVideoMatrixCoefficients::Rgb, true }); + auto videoFrame = VideoFrame::createFromPixelBuffer(pixelBuffer.releaseNonNull(), { .primaries = PlatformVideoColorPrimaries::Bt709, .transfer = PlatformVideoTransferCharacteristics::Iec6196621, .matrix = PlatformVideoMatrixCoefficients::Rgb, .fullRange = true }); if (!videoFrame) return Exception { ExceptionCode::InvalidStateError, "Unable to create frame from buffer"_s }; diff --git a/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrameAlgorithms.cpp b/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrameAlgorithms.cpp index 0b5ec95978d9..9fe8c2da7324 100644 --- a/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrameAlgorithms.cpp +++ b/Source/WebCore/Modules/webcodecs/WebCodecsVideoFrameAlgorithms.cpp @@ -268,9 +268,9 @@ VideoColorSpaceInit videoFramePickColorSpace(const std::optionaltoStringView().endsWith('\n'); } -// |lineRange| ending where the text control's value ends, rather than where its rendered text does. -// A line that ends with the collapsed trailing newline is one character longer than the line of the -// value it stands for, and for the empty final line that newline is the whole range. Marker walks are -// left the unclamped range, so that empty final line remains enumerable as a line of its own. -static AXTextMarkerRange lineRangeWithoutCollapsedTrailingNewline(const AXTextMarkerRange& lineRange) +enum class LineRangeTrim : uint8_t { + // A text control's value ends before the newline its rendered text ends with. + // This option allows explicit trimming of this collapsed newline. + CollapsedTrailingNewline = 1 << 0, + // The text runs keep the space a line soft-wrapped at, appended to the wrapping line's run, so a + // range spanning the wrap reads "foo bar" rather than "foobar". This space renders on no line, so + // no line ends with it. This option denotes it should be trimmed. + SoftWrapSpace = 1 << 1, +}; + +static AXTextMarkerRange lineRangeWithout(const AXTextMarkerRange& lineRange, OptionSet trims) { auto endMarker = lineRange.end().toTextRunMarker(); RefPtr endObject = endMarker.isolatedObject(); - if (!endObject) + const auto* runs = endObject ? endObject->textRuns() : nullptr; + if (!runs) return lineRange; - auto indexOfCollapsedNewline = offsetOfCollapsedTrailingNewline(*endObject, endObject->textRuns()); - if (!indexOfCollapsedNewline || endMarker.offset() <= *indexOfCollapsedNewline) + unsigned endOffset = endMarker.offset(); + if (trims.contains(LineRangeTrim::CollapsedTrailingNewline)) { + std::optional offsetOfNewline = offsetOfCollapsedTrailingNewline(*endObject, runs); + if (offsetOfNewline && endOffset > *offsetOfNewline) + endOffset = *offsetOfNewline; + } + + if (trims.contains(LineRangeTrim::SoftWrapSpace)) { + // Only a line that ended where this object wrapped has a wrap space, as its end + // sits at the end of a run that another follows. + // + // For example, in this text where _ is a wrap-space and | is the text position: + // aaa_| + // bbb + // We want to trim the space after "aaa" if this option is set. + size_t runIndex = runs->indexForOffset(endOffset, Affinity::Upstream); + bool endsWhereObjectWrapped = runIndex != notFound && runIndex != runs->lastRunIndex() && runs->runLengthSumTo(runIndex) == endOffset; + if (endsWhereObjectWrapped && endOffset && runs->toStringView()[endOffset - 1] == space) + --endOffset; + } + + if (endOffset == endMarker.offset()) + return lineRange; + + if (lineRange.start().objectID() == endMarker.objectID() && lineRange.start().offset() > endOffset) { + // Trimming the range would move the end before the start, so early-exit. return lineRange; - return { lineRange.start(), AXTextMarker { *endObject, *indexOfCollapsedNewline } }; + } + return { lineRange.start(), AXTextMarker { *endObject, endOffset } }; } // Advances |lineRange| to the following line: the range from the start of the next line through @@ -898,7 +930,7 @@ CharacterRange AXTextMarker::characterRangeForLine(unsigned lineIndex) const // the preceding line's range), which is why only block-separated lines were affected. unsigned precedingLength = AXTextMarkerRange { textRunMarker, currentLineRange.start() }.length(); - return CharacterRange(precedingLength, lineRangeWithoutCollapsedTrailingNewline(currentLineRange).length()); + return CharacterRange(precedingLength, lineRangeWithout(currentLineRange, LineRangeTrim::CollapsedTrailingNewline).length()); } AXTextMarkerRange AXTextMarker::markerRangeForLineIndex(unsigned lineIndex) const @@ -916,7 +948,7 @@ AXTextMarkerRange AXTextMarker::markerRangeForLineIndex(unsigned lineIndex) cons currentLineRange = nextLineRange(currentLineRange, IncludeTrailingLineBreak::No, std::nullopt); --lineIndex; } - return lineRangeWithoutCollapsedTrailingNewline(currentLineRange); + return lineRangeWithout(currentLineRange, { LineRangeTrim::CollapsedTrailingNewline, LineRangeTrim::SoftWrapSpace }); } int AXTextMarker::lineNumberForIndex(unsigned index) const @@ -938,7 +970,7 @@ int AXTextMarker::lineNumberForIndex(unsigned index) const unsigned lineNumber = 0; auto currentLineRange = textRunMarker.lineRange(LineRangeType::Current, IncludeTrailingLineBreak::Yes); while (currentLineRange) { - unsigned lineLength = lineRangeWithoutCollapsedTrailingNewline(currentLineRange).length(); + unsigned lineLength = lineRangeWithout(currentLineRange, LineRangeTrim::CollapsedTrailingNewline).length(); auto nextRange = nextLineRange(currentLineRange, IncludeTrailingLineBreak::Yes, stopAtID); // A line occupies the index space up to the start of the next line, which is not the same as // the length of its own range: the newline synthesized at a block boundary belongs to no @@ -1788,7 +1820,7 @@ AXTextMarkerRange AXTextMarker::lineRange(LineRangeType type, IncludeTrailingLin if (type == LineRangeType::Current) { auto startMarker = atLineStart() ? *this : previousLineStart(); auto endMarker = atLineEnd() ? *this : nextLineEnd(includeTrailingLineBreak); - return lineRangeWithoutCollapsedTrailingNewline({ startMarker, endMarker }); + return lineRangeWithout({ startMarker, endMarker }, LineRangeTrim::CollapsedTrailingNewline); } if (type == LineRangeType::Left) { @@ -1798,7 +1830,7 @@ AXTextMarkerRange AXTextMarker::lineRange(LineRangeType type, IncludeTrailingLin startMarker = startMarker.previousLineStart(); auto endMarker = startMarker.nextLineEnd(includeTrailingLineBreak); - return lineRangeWithoutCollapsedTrailingNewline({ WTF::move(startMarker), WTF::move(endMarker) }); + return lineRangeWithout({ WTF::move(startMarker), WTF::move(endMarker) }, LineRangeTrim::CollapsedTrailingNewline); } AX_ASSERT(type == LineRangeType::Right); @@ -1809,7 +1841,7 @@ AXTextMarkerRange AXTextMarker::lineRange(LineRangeType type, IncludeTrailingLin startMarker = startMarker.previousLineStart(); auto endMarker = startMarker.nextLineEnd(includeTrailingLineBreak); - return lineRangeWithoutCollapsedTrailingNewline({ WTF::move(startMarker), WTF::move(endMarker) }); + return lineRangeWithout({ WTF::move(startMarker), WTF::move(endMarker) }, LineRangeTrim::CollapsedTrailingNewline); } AXTextMarkerRange AXTextMarker::wordRange(WordRangeType type) const diff --git a/Source/WebCore/accessibility/AccessibilityMenuList.cpp b/Source/WebCore/accessibility/AccessibilityMenuList.cpp index 82058fa189df..7de9e2acacab 100644 --- a/Source/WebCore/accessibility/AccessibilityMenuList.cpp +++ b/Source/WebCore/accessibility/AccessibilityMenuList.cpp @@ -48,8 +48,6 @@ AccessibilityMenuList::AccessibilityMenuList(AXID axID, RenderObject& renderer, Ref AccessibilityMenuList::create(AXID axID, RenderObject& renderer, AXObjectCache& cache) { Ref menuList = adoptRef(*new AccessibilityMenuList(axID, renderer, cache)); - // We have to do this setup here and not in the constructor to avoid an - // adoptionIsRequired ASSERT in RefCounted.h. menuList->m_popup->setParent(menuList.ptr()); menuList->addChild(menuList->m_popup.get()); menuList->m_childrenInitialized = true; diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp index 2993967e00fb..9c32c1a1ab28 100644 --- a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp @@ -1107,15 +1107,6 @@ static bool NODELETE isFlowContent(Node& node) return text && !text->data().containsOnly(); } -bool AccessibilityNodeObject::isNativeTextControl() const -{ - if (is(node())) - return true; - - auto* input = dynamicDowncast(node()); - return input && (input->isText() || input->isNumberField()); -} - bool AccessibilityNodeObject::isSearchField() const { RefPtr node = this->node(); @@ -4135,9 +4126,9 @@ String AccessibilityNodeObject::text() const if (!isTextControl()) return { }; + if (RefPtr textControl = nativeTextControl()) + return textControl->value(); RefPtr element = dynamicDowncast(node()); - if (RefPtr formControl = dynamicDowncast(element); formControl && isNativeTextControl()) - return formControl->value(); return element ? element->innerText() : String(); } diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.h b/Source/WebCore/accessibility/AccessibilityNodeObject.h index d43f643c8b3e..1319864b2d88 100644 --- a/Source/WebCore/accessibility/AccessibilityNodeObject.h +++ b/Source/WebCore/accessibility/AccessibilityNodeObject.h @@ -65,7 +65,6 @@ class AccessibilityNodeObject : public AccessibilityObject { bool isDescriptionList() const final; bool isMultiSelectable() const override; bool NODELETE isNativeImage() const; - bool isNativeTextControl() const final; bool isSecureField() const final; bool isSearchField() const final; diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp index 628258691d90..6d31596a9f8d 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp @@ -68,6 +68,7 @@ #include "FrameSelection.h" #include "GeometryUtilities.h" #include "HTMLAreaElement.h" +#include "HTMLBRElement.h" #include "HTMLBodyElement.h" #include "HTMLDataListElement.h" #include "HTMLDetailsElement.h" @@ -945,6 +946,38 @@ std::optional AccessibilityObject::simpleRange() const return AXObjectCache::rangeForNodeContents(*node); } +HTMLTextFormControlElement* AccessibilityObject::nativeTextControl() const +{ + if (auto* textArea = dynamicDowncast(node())) + return textArea; + + auto* input = dynamicDowncast(node()); + return input && (input->isText() || input->isNumberField()) ? input : nullptr; +} + +AXTextMarkerRange AccessibilityObject::textMarkerRange() const +{ + // A native text control's value lives in its shadow inner text element, so the host has no + // children whose contents to take: simpleRange covers the control as a single replaced object, + // which stringifies to an object replacement character rather than the value. + if (RefPtr textControl = nativeTextControl()) { + if (RefPtr innerText = textControl->innerTextElement()) { + auto range = AXObjectCache::rangeForNodeContents(*innerText); + // A value ending in a line break renders an empty final line, which + // HTMLTextFormControlElement::setInnerTextValue gives a line box by appending a + // placeholder
. That
's newline is collapsed out by rendering and is not a + // character of the value, so leave it out. + if (is(innerText->lastChild()) && range.end.offset) + --range.end.offset; + // A control with no value has no text to point at, so leave it pointing at itself, + // which is the only marker its callers can place in the document. + if (range.start != range.end) + return AXTextMarkerRange { std::optional { range } }; + } + } + return simpleRange(); +} + Vector AccessibilityObject::previousLineStartBoundaryPoints(const VisiblePosition& startingPosition, const SimpleRange& targetRange, unsigned positionsToRetrieve) const { Vector boundaryPoints; @@ -2928,7 +2961,19 @@ bool AccessibilityObject::replaceTextInRange(const String& replacementString, co // Also only do this when the field is in editing mode. Ref frame = renderer()->frame(); if (element->shouldUseInputMethod()) { - frame->selection().setSelectedRange(rangeForCharacterRange(range), Affinity::Downstream, FrameSelection::ShouldCloseTyping::Yes); + uint64_t textLength = getLengthForTextRange(); + uint64_t startIndex = std::min(range.location, textLength); + uint64_t endIndex = startIndex + std::min(range.length, textLength - startIndex); + + auto start = visiblePositionForIndex(static_cast(startIndex)); + std::optional insertionRange = makeSimpleRange(start, endIndex == startIndex ? start : visiblePositionForIndex(static_cast(endIndex))); + if (!insertionRange) + return false; + + // Fail if the selection can't be set, otherwise the wrong text would be replaced. + if (!frame->selection().setSelectedRange(*insertionRange, Affinity::Downstream, FrameSelection::ShouldCloseTyping::Yes)) + return false; + protect(frame->editor())->replaceSelectionWithText(replacementString, Editor::SelectReplacement::No, Editor::SmartReplace::No); return true; } diff --git a/Source/WebCore/accessibility/AccessibilityObject.h b/Source/WebCore/accessibility/AccessibilityObject.h index f8b1c21446b6..b74bf682977f 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.h +++ b/Source/WebCore/accessibility/AccessibilityObject.h @@ -64,6 +64,7 @@ WTF_ALLOW_COMPACT_POINTERS_TO_INCOMPLETE_TYPE(WebCore::AXObjectRareData); namespace WebCore { +class HTMLTextFormControlElement; class IntPoint; class IntSize; class ScrollableArea; @@ -140,7 +141,9 @@ class AccessibilityObject : public AXCoreObject { bool isSecureField() const override { return false; } bool isContainedBySecureField() const; - bool isNativeTextControl() const override { return false; } + bool isNativeTextControl() const final { return nativeTextControl(); } + // The