aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dispatch-workflow.yml6
-rw-r--r--.github/workflows/linux.yml6
-rw-r--r--.github/workflows/mac.yml6
-rw-r--r--.github/workflows/main.yml1
-rw-r--r--.github/workflows/ohos.yml6
-rw-r--r--.github/workflows/try-label.yml1
-rw-r--r--.github/workflows/try.yml6
-rw-r--r--.github/workflows/windows.yml6
-rw-r--r--Cargo.lock133
-rw-r--r--components/compositing/webview_renderer.rs5
-rw-r--r--components/constellation/constellation.rs73
-rw-r--r--components/constellation/tracing.rs5
-rw-r--r--components/layout/construct_modern.rs2
-rw-r--r--components/layout/display_list/mod.rs66
-rw-r--r--components/layout/dom.rs79
-rw-r--r--components/layout/dom_traversal.rs33
-rw-r--r--components/layout/flexbox/layout.rs13
-rw-r--r--components/layout/flexbox/mod.rs23
-rw-r--r--components/layout/flow/construct.rs173
-rw-r--r--components/layout/flow/inline/construct.rs71
-rw-r--r--components/layout/flow/inline/inline_box.rs26
-rw-r--r--components/layout/flow/inline/line.rs21
-rw-r--r--components/layout/flow/inline/mod.rs85
-rw-r--r--components/layout/flow/inline/text_run.rs72
-rw-r--r--components/layout/flow/mod.rs58
-rw-r--r--components/layout/flow/root.rs8
-rw-r--r--components/layout/formatting_contexts.rs28
-rw-r--r--components/layout/fragment_tree/box_fragment.rs11
-rw-r--r--components/layout/fragment_tree/fragment.rs27
-rw-r--r--components/layout/fragment_tree/positioning_fragment.rs17
-rw-r--r--components/layout/layout_box_base.rs8
-rw-r--r--components/layout/layout_impl.rs10
-rw-r--r--components/layout/lib.rs11
-rw-r--r--components/layout/positioned.rs287
-rw-r--r--components/layout/table/construct.rs22
-rw-r--r--components/layout/table/layout.rs1
-rw-r--r--components/layout/table/mod.rs59
-rw-r--r--components/layout/taffy/mod.rs24
-rw-r--r--components/layout/traversal.rs82
-rw-r--r--components/malloc_size_of/lib.rs7
-rw-r--r--components/net/http_loader.rs16
-rw-r--r--components/net/tests/http_loader.rs8
-rw-r--r--components/script/body.rs14
-rw-r--r--components/script/dom/attr.rs10
-rw-r--r--components/script/dom/bindings/structuredclone.rs7
-rw-r--r--components/script/dom/create.rs2
-rw-r--r--components/script/dom/element.rs138
-rw-r--r--components/script/dom/globalscope.rs4
-rw-r--r--components/script/dom/htmliframeelement.rs26
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/node.rs3
-rw-r--r--components/script/dom/promise.rs17
-rw-r--r--components/script/dom/readablestream.rs7
-rw-r--r--components/script/dom/svgelement.rs3
-rw-r--r--components/script/dom/svgimageelement.rs96
-rw-r--r--components/script/dom/transformstream.rs106
-rw-r--r--components/script/dom/trustedhtml.rs18
-rw-r--r--components/script/dom/virtualmethods.rs4
-rw-r--r--components/script/messaging.rs1
-rw-r--r--components/script/script_thread.rs57
-rw-r--r--components/script/webdriver_handlers.rs2
-rw-r--r--components/script_bindings/codegen/Bindings.conf4
-rw-r--r--components/script_bindings/codegen/CodegenRust.py97
-rw-r--r--components/script_bindings/import.rs6
-rw-r--r--components/script_bindings/interfaces.rs19
-rw-r--r--components/script_bindings/webidls/Element.webidl8
-rw-r--r--components/script_bindings/webidls/HTMLIFrameElement.webidl4
-rw-r--r--components/script_bindings/webidls/SVGElement.webidl2
-rw-r--r--components/script_bindings/webidls/SVGImageElement.webidl16
-rw-r--r--components/servo/javascript_evaluator.rs65
-rw-r--r--components/servo/lib.rs16
-rw-r--r--components/servo/tests/webview.rs82
-rw-r--r--components/servo/webview.rs23
-rw-r--r--components/shared/constellation/from_script_message.rs9
-rw-r--r--components/shared/constellation/lib.rs9
-rw-r--r--components/shared/constellation/structured_data/mod.rs3
-rw-r--r--components/shared/constellation/structured_data/serializable.rs6
-rw-r--r--components/shared/constellation/structured_data/transferable.rs6
-rw-r--r--components/shared/embedder/lib.rs64
-rw-r--r--components/shared/net/request.rs4
-rw-r--r--components/shared/script/lib.rs7
-rw-r--r--components/shared/script_layout/lib.rs1
-rw-r--r--components/webdriver_server/actions.rs54
-rw-r--r--python/servo/try_parser.py33
-rw-r--r--tests/wpt/meta/MANIFEST.json15
-rw-r--r--tests/wpt/meta/content-security-policy/reporting/report-clips-sample.https.html.ini3
-rw-r--r--tests/wpt/meta/fetch/metadata/generated/svg-image.https.sub.html.ini47
-rw-r--r--tests/wpt/meta/fetch/metadata/generated/svg-image.sub.html.ini37
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini60
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html.ini24
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini36
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-serializable.html.ini15
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini15
-rw-r--r--tests/wpt/meta/html/dom/idlharness.https.html.ini228
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini8
-rw-r--r--tests/wpt/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini450
-rw-r--r--tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini9
-rw-r--r--tests/wpt/meta/streams/transferable/transform-stream.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini24
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html.ini12
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-Element-outerHTML.html.ini15
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setAttribute.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html.ini12
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini12
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLIFrameElement-srcdoc.html.ini9
-rw-r--r--tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini9
-rw-r--r--tests/wpt/meta/trusted-types/default-policy.html.ini22
-rw-r--r--tests/wpt/meta/trusted-types/empty-default-policy.html.ini7
-rw-r--r--tests/wpt/meta/trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html.ini18
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini24
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini6
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-innerHTML.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-insertAdjacentHTML.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-outerHTML.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-setHTMLUnsafe.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement-innerHTML.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting-for-SVGScriptElement-innerHTML.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-sandbox-allow-scripts.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-source-file-path.html.ini9
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json2
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.https.html1
-rw-r--r--tests/wpt/tests/css/css-display/display-contents-inline-002.html18
-rw-r--r--tests/wpt/tests/css/cssom-view/table-client-props.html13
128 files changed, 2099 insertions, 1758 deletions
diff --git a/.github/workflows/dispatch-workflow.yml b/.github/workflows/dispatch-workflow.yml
index 472f4813cd7..2e4b8ef7076 100644
--- a/.github/workflows/dispatch-workflow.yml
+++ b/.github/workflows/dispatch-workflow.yml
@@ -8,6 +8,9 @@ on:
profile:
required: true
type: string
+ build-args:
+ required: true
+ type: string
wpt-args:
required: true
type: string
@@ -35,6 +38,7 @@ jobs:
secrets: inherit
with:
profile: ${{ inputs.profile }}
+ build-args: ${{ inputs.build-args }}
unit-tests: ${{ inputs.unit-tests }}
build-libservo: ${{ inputs.build-libservo }}
bencher: ${{ inputs.bencher }}
@@ -46,6 +50,7 @@ jobs:
secrets: inherit
with:
profile: ${{ inputs.profile }}
+ build-args: ${{ inputs.build-args }}
wpt: ${{ inputs.wpt }}
unit-tests: ${{ inputs.unit-tests }}
build-libservo: ${{ inputs.build-libservo }}
@@ -59,6 +64,7 @@ jobs:
secrets: inherit
with:
profile: ${{ inputs.profile }}
+ build-args: ${{ inputs.build-args }}
wpt: ${{ inputs.wpt }}
number-of-wpt-chunks: ${{ inputs.number-of-wpt-chunks }}
unit-tests: ${{ inputs.unit-tests }}
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 033f9795a23..b47f1906160 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -6,6 +6,10 @@ on:
required: false
default: "release"
type: string
+ build-args:
+ default: ""
+ required: false
+ type: string
wpt-args:
default: ""
required: false
@@ -166,7 +170,7 @@ jobs:
- name: Build (${{ inputs.profile }})
run: |
- ./mach build --use-crown --locked --${{ inputs.profile }}
+ ./mach build --use-crown --locked --${{ inputs.profile }} ${{ inputs.build-args }}
cp -r target/cargo-timings target/cargo-timings-linux
- name: Smoketest
run: xvfb-run ./mach smoketest --${{ inputs.profile }}
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index e27c0a54180..4c19def57d2 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -7,6 +7,10 @@ on:
required: false
default: "release"
type: string
+ build-args:
+ default: ""
+ required: false
+ type: string
wpt-args:
default: ""
required: false
@@ -146,7 +150,7 @@ jobs:
brew install gnu-tar
- name: Build (${{ inputs.profile }})
run: |
- ./mach build --use-crown --locked --${{ inputs.profile }}
+ ./mach build --use-crown --locked --${{ inputs.profile }} ${{ inputs.build-args }}
cp -r target/cargo-timings target/cargo-timings-macos
- name: Smoketest
uses: nick-fields/retry@v3
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 1545dfa2450..1d11033a326 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -56,6 +56,7 @@ jobs:
unit-tests: ${{ matrix.unit_tests }}
build-libservo: ${{ matrix.build_libservo }}
wpt-args: ${{ matrix.wpt_args }}
+ build-args: ${{ matrix.build_args }}
number-of-wpt-chunks: ${{ matrix.number_of_wpt_chunks }}
bencher: ${{ matrix.bencher }}
diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml
index 8728d31865c..505186903b0 100644
--- a/.github/workflows/ohos.yml
+++ b/.github/workflows/ohos.yml
@@ -223,10 +223,8 @@ jobs:
hdc shell snapshot_display -f /data/local/tmp/servo.jpeg
hdc file recv /data/local/tmp/servo.jpeg test_output/servo_hos_screenshot.jpeg
hdc file recv /data/local/tmp/ohtrace.txt test_output/servo.ftrace
- # To limit the logsize we only save logs from servo.
- # Todo: investigate giving servo a custom domain tag, so we can also log appspawn etc,
- # since another common error might be the dynamic loader failing to relocate libservoshell.so
- hdc shell hilog --exit --pid=${servo_pid} > test_output/servo.log
+ # To limit the logsize we only save logs from servo.
+ hdc shell hilog --exit -D 0xE0C3 > test_output/servo.log
# todo: Also benchmark some other websites....
- name: Upload artifacts
uses: actions/upload-artifact@v4
diff --git a/.github/workflows/try-label.yml b/.github/workflows/try-label.yml
index b1ca27a6f58..d4ce3f944f6 100644
--- a/.github/workflows/try-label.yml
+++ b/.github/workflows/try-label.yml
@@ -128,6 +128,7 @@ jobs:
unit-tests: ${{ matrix.unit_tests }}
build-libservo: ${{ matrix.build_libservo }}
wpt-args: ${{ matrix.wpt_args }}
+ build-args: ${{ matrix.build_args }}
number-of-wpt-chunks: ${{ matrix.number_of_wpt_chunks }}
bencher: ${{ matrix.bencher }}
diff --git a/.github/workflows/try.yml b/.github/workflows/try.yml
index cba4fc03e06..c3a49af8857 100644
--- a/.github/workflows/try.yml
+++ b/.github/workflows/try.yml
@@ -10,6 +10,10 @@ on:
default: "release"
type: choice
options: ["release", "debug", "production"]
+ build-args:
+ default: ""
+ required: false
+ type: string
wpt-args:
default: ""
required: false
@@ -79,6 +83,7 @@ jobs:
// WPT-related overrides only affect Linux currently, as tests don't run by default on other platforms.
configuration.matrix[0].wpt = Boolean(${{ inputs.wpt }});
configuration.matrix[0].wpt_args = "${{ inputs.wpt-args }}" || "";
+ configuration.matrix[0].build_args = "${{ inputs.build-args }}" || "";
let unit_tests = Boolean(${{ inputs.unit-tests }});
let profile = '${{ inputs.profile }}';
@@ -107,6 +112,7 @@ jobs:
profile: ${{ matrix.profile }}
unit-tests: ${{ matrix.unit_tests }}
build-libservo: ${{ matrix.build_libservo }}
+ build-args: ${{ matrix.build_args }}
wpt-args: ${{ matrix.wpt_args }}
number-of-wpt-chunks: ${{ matrix.number_of_wpt_chunks }}
bencher: ${{ matrix.bencher }}
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 5cf1e50b853..93e1710e464 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -7,6 +7,10 @@ on:
required: false
default: "release"
type: string
+ build-args:
+ default: ""
+ required: false
+ type: string
unit-tests:
required: false
default: false
@@ -161,7 +165,7 @@ jobs:
- name: Build (${{ inputs.profile }})
run: |
- .\mach build --use-crown --locked --${{ inputs.profile }}
+ .\mach build --use-crown --locked --${{ inputs.profile }} ${{ inputs.build-args }}
cp C:\a\servo\servo\target\cargo-timings C:\a\servo\servo\target\cargo-timings-windows -Recurse
- name: Copy resources
if: ${{ runner.environment != 'self-hosted' }}
diff --git a/Cargo.lock b/Cargo.lock
index 8b2f157cc1a..fb0e0679b69 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -526,7 +526,7 @@ dependencies = [
"bitflags 2.9.0",
"cexpr",
"clang-sys",
- "itertools 0.13.0",
+ "itertools 0.10.5",
"proc-macro2",
"quote",
"regex",
@@ -964,18 +964,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.37"
+version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.37"
+version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
dependencies = [
"anstyle",
"clap_lex",
@@ -1065,7 +1065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -2032,7 +2032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2551,15 +2551,15 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "gio-sys"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e"
+checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2584,9 +2584,9 @@ dependencies = [
[[package]]
name = "glib"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707b819af8059ee5395a2de9f2317d87a53dbad8846a2f089f0bb44703f37686"
+checksum = "c501c495842c2b23cdacead803a5a343ca2a5d7a7ddaff14cc5f6cf22cfb92c2"
dependencies = [
"bitflags 2.9.0",
"futures-channel",
@@ -2605,9 +2605,9 @@ dependencies = [
[[package]]
name = "glib-macros"
-version = "0.20.7"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68"
+checksum = "ebe6dc9ce29887c4b3b74d78d5ba473db160a258ae7ed883d23632ac7fed7bc9"
dependencies = [
"heck",
"proc-macro-crate",
@@ -2618,9 +2618,9 @@ dependencies = [
[[package]]
name = "glib-sys"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb"
+checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215"
dependencies = [
"libc",
"system-deps",
@@ -2664,9 +2664,9 @@ dependencies = [
[[package]]
name = "gobject-sys"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3"
+checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda"
dependencies = [
"glib-sys",
"libc",
@@ -2732,9 +2732,9 @@ checksum = "36119f3a540b086b4e436bb2b588cf98a68863470e0e880f4d0842f112a3183a"
[[package]]
name = "gstreamer"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2188fe829b0ebe12e4cf2bbcf6658470a936269daba7afae92847a2af32c9105"
+checksum = "50ab4c88f731596a2511a6f14cabdd666e0d8efab62a1d58e6ddb57faa96e22e"
dependencies = [
"cfg-if",
"futures-channel",
@@ -2742,7 +2742,7 @@ dependencies = [
"futures-util",
"glib",
"gstreamer-sys",
- "itertools 0.13.0",
+ "itertools 0.14.0",
"libc",
"muldiv",
"num-integer",
@@ -2785,9 +2785,9 @@ dependencies = [
[[package]]
name = "gstreamer-audio"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49118ca684e2fc42207509fcac8497d91079c2ffe8ff2b4ae99e71dbafef1ede"
+checksum = "2e7ec7e0374298897e669db7c79544bc44df12011985e7dd5f38644edaf2caf4"
dependencies = [
"cfg-if",
"glib",
@@ -2801,9 +2801,9 @@ dependencies = [
[[package]]
name = "gstreamer-audio-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d469526ecf30811b50a6460fd285ee40d189c46048b3d0c69b67a04b414fb51"
+checksum = "2b5f3e09e7c04ec91d78c2a6ca78d50b574b9ed49fdf5e72f3693adca4306a87"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -2815,9 +2815,9 @@ dependencies = [
[[package]]
name = "gstreamer-base"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad33dd444db0d215ac363164f900f800ffb93361ad8a60840e95e14b7de985e8"
+checksum = "f19a74fd04ffdcb847dd322640f2cf520897129d00a7bcb92fd62a63f3e27404"
dependencies = [
"atomic_refcell",
"cfg-if",
@@ -2829,9 +2829,9 @@ dependencies = [
[[package]]
name = "gstreamer-base-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "114b2a704f19a70f20c54b00e54f5d5376bbf78bd2791e6beb0776c997d8bf24"
+checksum = "87f2fb0037b6d3c5b51f60dea11e667910f33be222308ca5a101450018a09840"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -2842,9 +2842,9 @@ dependencies = [
[[package]]
name = "gstreamer-gl"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02818bd81028abc4ee7b0106c21625be9a2f86ba5fd41ccff58359537637db59"
+checksum = "34aa19feafc4da2c7635abce0e0768892ff97ad73586bef02d9a60b251d9fe09"
dependencies = [
"glib",
"gstreamer",
@@ -2857,9 +2857,9 @@ dependencies = [
[[package]]
name = "gstreamer-gl-egl"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc5fad98961d18ed5dba4be44787d4735b78a1f53b7db392be004b96f1f2430b"
+checksum = "8de1f4247cf2d009b41ab5efb03e4d826b7ccaafb9a75d3ea10e68e46f65e8aa"
dependencies = [
"glib",
"gstreamer",
@@ -2870,9 +2870,9 @@ dependencies = [
[[package]]
name = "gstreamer-gl-egl-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7ebdc94dc34e2b135b2610676b47d30ce88b80862f01e2acf7e29b9b42a14e4"
+checksum = "dda4d852ed107cc48692af4e109e5e4775b6ce1044d13df79f6f431c195096d7"
dependencies = [
"glib-sys",
"gstreamer-gl-sys",
@@ -2882,9 +2882,9 @@ dependencies = [
[[package]]
name = "gstreamer-gl-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2984f8c246407fabbecf852c4595dd1487f4cc495386e17ad31acb69db7d39"
+checksum = "a832c21d4522ed5e1b8dfc676a45361969216b144fc03af413a38c471f38bcf7"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -2972,9 +2972,9 @@ dependencies = [
[[package]]
name = "gstreamer-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe159238834058725808cf6604a7c5d9e4a50e1eacd7b0c63bce2fe3a067dbd1"
+checksum = "feea73b4d92dbf9c24a203c9cd0bcc740d584f6b5960d5faf359febf288919b2"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -2984,9 +2984,9 @@ dependencies = [
[[package]]
name = "gstreamer-video"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad242d388b63c91652c8157de3b0c1f709e49c941a0aae1952455f6ee326ca2d"
+checksum = "1318b599d77ca4f7702ecbdeac1672d6304cb16b7e5752fabb3ee8260449a666"
dependencies = [
"cfg-if",
"futures-channel",
@@ -3001,9 +3001,9 @@ dependencies = [
[[package]]
name = "gstreamer-video-sys"
-version = "0.23.5"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "465ff496889fb38be47f5e821163c2e83414d87c4aa55f5aae62dc7200971d4d"
+checksum = "0a70f0947f12d253b9de9bc3fd92f981e4d025336c18389c7f08cdf388a99f5c"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -4001,7 +4001,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi 0.5.0",
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -4021,15 +4021,6 @@ dependencies = [
[[package]]
name = "itertools"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
@@ -4258,12 +4249,12 @@ dependencies = [
[[package]]
name = "libloading"
-version = "0.8.6"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
dependencies = [
"cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.48.5",
]
[[package]]
@@ -6191,7 +6182,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -6524,7 +6515,7 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.28.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"bitflags 2.9.0",
"cssparser",
@@ -6819,7 +6810,7 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.4.1"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"serde",
"stable_deref_trait",
@@ -7280,7 +7271,7 @@ dependencies = [
[[package]]
name = "stylo"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"app_units",
"arrayvec",
@@ -7338,7 +7329,7 @@ dependencies = [
[[package]]
name = "stylo_atoms"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"string_cache",
"string_cache_codegen",
@@ -7347,12 +7338,12 @@ dependencies = [
[[package]]
name = "stylo_config"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
[[package]]
name = "stylo_derive"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"darling",
"proc-macro2",
@@ -7364,7 +7355,7 @@ dependencies = [
[[package]]
name = "stylo_dom"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"bitflags 2.9.0",
"stylo_malloc_size_of",
@@ -7373,7 +7364,7 @@ dependencies = [
[[package]]
name = "stylo_malloc_size_of"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"app_units",
"cssparser",
@@ -7390,12 +7381,12 @@ dependencies = [
[[package]]
name = "stylo_static_prefs"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
[[package]]
name = "stylo_traits"
version = "0.3.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"app_units",
"bitflags 2.9.0",
@@ -7559,7 +7550,7 @@ dependencies = [
"getrandom",
"once_cell",
"rustix",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -7778,7 +7769,7 @@ dependencies = [
[[package]]
name = "to_shmem"
version = "0.2.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"cssparser",
"servo_arc",
@@ -7791,7 +7782,7 @@ dependencies = [
[[package]]
name = "to_shmem_derive"
version = "0.1.0"
-source = "git+https://github.com/servo/stylo?branch=2025-05-01#7edd19e2f09570c6734161b4bb7d47859c8699bf"
+source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea"
dependencies = [
"darling",
"proc-macro2",
@@ -8916,7 +8907,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs
index f76dc68013d..a51dd5f8cda 100644
--- a/components/compositing/webview_renderer.rs
+++ b/components/compositing/webview_renderer.rs
@@ -689,11 +689,6 @@ impl WebViewRenderer {
action: MouseButtonAction::Up,
point,
}));
- self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent {
- button,
- action: MouseButtonAction::Click,
- point,
- }));
}
pub(crate) fn notify_scroll_event(
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index e493a97d184..5db37800c42 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -129,9 +129,10 @@ use embedder_traits::resources::{self, Resource};
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{
AnimationState, CompositorHitTestResult, Cursor, EmbedderMsg, EmbedderProxy,
- FocusSequenceNumber, ImeEvent, InputEvent, MediaSessionActionType, MediaSessionEvent,
- MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent, Theme,
- ViewportDetails, WebDriverCommandMsg, WebDriverLoadStatus,
+ FocusSequenceNumber, ImeEvent, InputEvent, JSValue, JavaScriptEvaluationError,
+ JavaScriptEvaluationId, MediaSessionActionType, MediaSessionEvent, MediaSessionPlaybackState,
+ MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverCommandMsg,
+ WebDriverLoadStatus,
};
use euclid::Size2D;
use euclid::default::Size2D as UntypedSize2D;
@@ -1477,6 +1478,52 @@ where
EmbedderToConstellationMessage::PaintMetric(pipeline_id, paint_metric_event) => {
self.handle_paint_metric(pipeline_id, paint_metric_event);
},
+ EmbedderToConstellationMessage::EvaluateJavaScript(
+ webview_id,
+ evaluation_id,
+ script,
+ ) => {
+ self.handle_evaluate_javascript(webview_id, evaluation_id, script);
+ },
+ }
+ }
+
+ #[cfg_attr(
+ feature = "tracing",
+ tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
+ )]
+ fn handle_evaluate_javascript(
+ &mut self,
+ webview_id: WebViewId,
+ evaluation_id: JavaScriptEvaluationId,
+ script: String,
+ ) {
+ let browsing_context_id = BrowsingContextId::from(webview_id);
+ let Some(pipeline) = self
+ .browsing_contexts
+ .get(&browsing_context_id)
+ .and_then(|browsing_context| self.pipelines.get(&browsing_context.pipeline_id))
+ else {
+ self.handle_finish_javascript_evaluation(
+ evaluation_id,
+ Err(JavaScriptEvaluationError::InternalError),
+ );
+ return;
+ };
+
+ if pipeline
+ .event_loop
+ .send(ScriptThreadMessage::EvaluateJavaScript(
+ pipeline.id,
+ evaluation_id,
+ script,
+ ))
+ .is_err()
+ {
+ self.handle_finish_javascript_evaluation(
+ evaluation_id,
+ Err(JavaScriptEvaluationError::InternalError),
+ );
}
}
@@ -1817,6 +1864,9 @@ where
self.mem_profiler_chan
.send(mem::ProfilerMsg::Report(sender));
},
+ ScriptToConstellationMessage::FinishJavaScriptEvaluation(evaluation_id, result) => {
+ self.handle_finish_javascript_evaluation(evaluation_id, result)
+ },
}
}
@@ -3182,6 +3232,22 @@ where
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)]
+ fn handle_finish_javascript_evaluation(
+ &mut self,
+ evaluation_id: JavaScriptEvaluationId,
+ result: Result<JSValue, JavaScriptEvaluationError>,
+ ) {
+ self.embedder_proxy
+ .send(EmbedderMsg::FinishJavaScriptEvaluation(
+ evaluation_id,
+ result,
+ ));
+ }
+
+ #[cfg_attr(
+ feature = "tracing",
+ tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
+ )]
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) {
let browsing_context_id = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.browsing_context_id,
@@ -4691,6 +4757,7 @@ where
NavigationHistoryBehavior::Replace,
);
},
+ // TODO: This should use the ScriptThreadMessage::EvaluateJavaScript command
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd) => {
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id,
diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs
index eff7f755c6b..fd7fe7dd251 100644
--- a/components/constellation/tracing.rs
+++ b/components/constellation/tracing.rs
@@ -77,6 +77,7 @@ mod from_compositor {
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
Self::SetScrollStates(..) => target!("SetScrollStates"),
Self::PaintMetric(..) => target!("PaintMetric"),
+ Self::EvaluateJavaScript(..) => target!("EvaluateJavaScript"),
}
}
}
@@ -176,6 +177,7 @@ mod from_script {
Self::TitleChanged(..) => target!("TitleChanged"),
Self::IFrameSizes(..) => target!("IFrameSizes"),
Self::ReportMemory(..) => target!("ReportMemory"),
+ Self::FinishJavaScriptEvaluation(..) => target!("FinishJavaScriptEvaluation"),
}
}
}
@@ -238,6 +240,9 @@ mod from_script {
Self::ShutdownComplete => target_variant!("ShutdownComplete"),
Self::ShowNotification(..) => target_variant!("ShowNotification"),
Self::ShowSelectElementMenu(..) => target_variant!("ShowSelectElementMenu"),
+ Self::FinishJavaScriptEvaluation(..) => {
+ target_variant!("FinishJavaScriptEvaluation")
+ },
}
}
}
diff --git a/components/layout/construct_modern.rs b/components/layout/construct_modern.rs
index 1489d82635b..8f1282ec9f6 100644
--- a/components/layout/construct_modern.rs
+++ b/components/layout/construct_modern.rs
@@ -142,7 +142,7 @@ impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
.filter_map(|job| match job {
ModernContainerJob::TextRuns(runs) => {
let mut inline_formatting_context_builder =
- InlineFormattingContextBuilder::new();
+ InlineFormattingContextBuilder::new(self.info);
for flex_text_run in runs.into_iter() {
inline_formatting_context_builder
.push_text(flex_text_run.text, &flex_text_run.info);
diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs
index d6cbb50e4a1..f017642908d 100644
--- a/components/layout/display_list/mod.rs
+++ b/components/layout/display_list/mod.rs
@@ -14,6 +14,7 @@ use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
use fonts::GlyphStore;
use gradient::WebRenderGradient;
use range::Range as ServoRange;
+use servo_arc::Arc as ServoArc;
use servo_geometry::MaxRect;
use style::Zero;
use style::color::{AbsoluteColor, ColorSpace};
@@ -470,18 +471,16 @@ impl Fragment {
Fragment::AbsoluteOrFixedPositioned(_) => {},
Fragment::Positioning(positioning_fragment) => {
let positioning_fragment = positioning_fragment.borrow();
- if let Some(style) = positioning_fragment.style.as_ref() {
- let rect = positioning_fragment
- .rect
- .translate(containing_block.origin.to_vector());
- self.maybe_push_hit_test_for_style_and_tag(
- builder,
- style,
- positioning_fragment.base.tag,
- rect,
- Cursor::Default,
- );
- }
+ let rect = positioning_fragment
+ .rect
+ .translate(containing_block.origin.to_vector());
+ self.maybe_push_hit_test_for_style_and_tag(
+ builder,
+ &positioning_fragment.style,
+ positioning_fragment.base.tag,
+ rect,
+ Cursor::Default,
+ );
},
Fragment::Image(image) => {
let image = image.borrow();
@@ -544,7 +543,13 @@ impl Fragment {
},
Fragment::Text(text) => {
let text = &*text.borrow();
- match text.parent_style.get_inherited_box().visibility {
+ match text
+ .inline_styles
+ .style
+ .borrow()
+ .get_inherited_box()
+ .visibility
+ {
Visibility::Visible => {
self.build_display_list_for_text_fragment(text, builder, containing_block)
},
@@ -604,22 +609,23 @@ impl Fragment {
return;
}
+ let parent_style = fragment.inline_styles.style.borrow();
self.maybe_push_hit_test_for_style_and_tag(
builder,
- &fragment.parent_style,
+ &parent_style,
fragment.base.tag,
rect,
Cursor::Text,
);
- let color = fragment.parent_style.clone_color();
+ let color = parent_style.clone_color();
let font_metrics = &fragment.font_metrics;
let dppx = builder.context.style_context.device_pixel_ratio().get();
- let common = builder.common_properties(rect.to_webrender(), &fragment.parent_style);
+ let common = builder.common_properties(rect.to_webrender(), &parent_style);
// Shadows. According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front to
// back).
- let shadows = &fragment.parent_style.get_inherited_text().text_shadow;
+ let shadows = &parent_style.get_inherited_text().text_shadow;
for shadow in shadows.0.iter().rev() {
builder.wr().push_shadow(
&wr::SpaceAndClipInfo {
@@ -642,7 +648,7 @@ impl Fragment {
let mut rect = rect;
rect.origin.y += font_metrics.ascent - font_metrics.underline_offset;
rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
- self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
+ self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
}
if fragment
@@ -651,7 +657,7 @@ impl Fragment {
{
let mut rect = rect;
rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
- self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
+ self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
}
// TODO: This caret/text selection implementation currently does not account for vertical text
@@ -678,12 +684,13 @@ impl Fragment {
Point2D::new(end.x.to_f32_px(), containing_block.max_y().to_f32_px()),
);
if let Some(selection_color) = fragment
- .selected_style
+ .inline_styles
+ .selected
+ .borrow()
.clone_background_color()
.as_absolute()
{
- let selection_common =
- builder.common_properties(selection_rect, &fragment.parent_style);
+ let selection_common = builder.common_properties(selection_rect, &parent_style);
builder.wr().push_rect(
&selection_common,
selection_rect,
@@ -709,7 +716,7 @@ impl Fragment {
),
);
let insertion_point_common =
- builder.common_properties(insertion_point_rect, &fragment.parent_style);
+ builder.common_properties(insertion_point_rect, &parent_style);
// TODO: The color of the caret is currently hardcoded to the text color.
// We should be retrieving the caret color from the style properly.
builder
@@ -734,7 +741,7 @@ impl Fragment {
let mut rect = rect;
rect.origin.y += font_metrics.ascent - font_metrics.strikeout_offset;
rect.size.height = Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx));
- self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
+ self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
}
if !shadows.0.is_empty() {
@@ -744,23 +751,22 @@ impl Fragment {
fn build_display_list_for_text_decoration(
&self,
- fragment: &TextFragment,
+ parent_style: &ServoArc<ComputedValues>,
builder: &mut DisplayListBuilder,
rect: &PhysicalRect<Au>,
color: &AbsoluteColor,
) {
let rect = rect.to_webrender();
let wavy_line_thickness = (0.33 * rect.size().height).ceil();
- let text_decoration_color = fragment
- .parent_style
+ let text_decoration_color = parent_style
.clone_text_decoration_color()
.resolve_to_absolute(color);
- let text_decoration_style = fragment.parent_style.clone_text_decoration_style();
+ let text_decoration_style = parent_style.clone_text_decoration_style();
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
return;
}
builder.display_list.wr.push_line(
- &builder.common_properties(rect, &fragment.parent_style),
+ &builder.common_properties(rect, parent_style),
&rect,
wavy_line_thickness,
wr::LineOrientation::Horizontal,
@@ -1026,7 +1032,7 @@ impl<'a> BuilderForBoxFragment<'a> {
for extra_background in extra_backgrounds {
let positioning_area = extra_background.rect;
let painter = BackgroundPainter {
- style: &extra_background.style.borrow_mut().0,
+ style: &extra_background.style.borrow_mut(),
painting_area_override: None,
positioning_area_override: Some(
positioning_area
diff --git a/components/layout/dom.rs b/components/layout/dom.rs
index 4400d78feb1..e3a22eb5197 100644
--- a/components/layout/dom.rs
+++ b/components/layout/dom.rs
@@ -19,14 +19,14 @@ use script_layout_interface::{
GenericLayoutDataTrait, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType,
};
use servo_arc::Arc as ServoArc;
+use style::context::SharedStyleContext;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use crate::cell::ArcRefCell;
-use crate::context::LayoutContext;
use crate::flexbox::FlexLevelBox;
use crate::flow::BlockLevelBox;
-use crate::flow::inline::InlineItem;
+use crate::flow::inline::{InlineItem, SharedInlineStyles};
use crate::fragment_tree::Fragment;
use crate::geom::PhysicalSize;
use crate::replaced::CanvasInfo;
@@ -59,7 +59,7 @@ impl InnerDOMLayoutData {
/// A box that is stored in one of the `DOMLayoutData` slots.
#[derive(MallocSizeOf)]
pub(super) enum LayoutBox {
- DisplayContents,
+ DisplayContents(SharedInlineStyles),
BlockLevel(ArcRefCell<BlockLevelBox>),
InlineLevel(Vec<ArcRefCell<InlineItem>>),
FlexLevel(ArcRefCell<FlexLevelBox>),
@@ -70,7 +70,7 @@ pub(super) enum LayoutBox {
impl LayoutBox {
fn invalidate_cached_fragment(&self) {
match self {
- LayoutBox::DisplayContents => {},
+ LayoutBox::DisplayContents(..) => {},
LayoutBox::BlockLevel(block_level_box) => {
block_level_box.borrow().invalidate_cached_fragment()
},
@@ -91,7 +91,7 @@ impl LayoutBox {
pub(crate) fn fragments(&self) -> Vec<Fragment> {
match self {
- LayoutBox::DisplayContents => vec![],
+ LayoutBox::DisplayContents(..) => vec![],
LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().fragments(),
LayoutBox::InlineLevel(inline_items) => inline_items
.iter()
@@ -102,6 +102,41 @@ impl LayoutBox {
LayoutBox::TableLevelBox(table_box) => table_box.fragments(),
}
}
+
+ fn repair_style(
+ &self,
+ context: &SharedStyleContext,
+ node: &ServoLayoutNode,
+ new_style: &ServoArc<ComputedValues>,
+ ) {
+ match self {
+ LayoutBox::DisplayContents(inline_shared_styles) => {
+ *inline_shared_styles.style.borrow_mut() = new_style.clone();
+ *inline_shared_styles.selected.borrow_mut() = node.to_threadsafe().selected_style();
+ },
+ LayoutBox::BlockLevel(block_level_box) => {
+ block_level_box
+ .borrow_mut()
+ .repair_style(context, node, new_style);
+ },
+ LayoutBox::InlineLevel(inline_items) => {
+ for inline_item in inline_items {
+ inline_item
+ .borrow_mut()
+ .repair_style(context, node, new_style);
+ }
+ },
+ LayoutBox::FlexLevel(flex_level_box) => {
+ flex_level_box.borrow_mut().repair_style(context, new_style)
+ },
+ LayoutBox::TableLevelBox(table_level_box) => {
+ table_level_box.repair_style(context, new_style)
+ },
+ LayoutBox::TaffyItemBox(taffy_item_box) => {
+ taffy_item_box.borrow_mut().repair_style(context, new_style)
+ },
+ }
+ }
}
/// A wrapper for [`InnerDOMLayoutData`]. This is necessary to give the entire data
@@ -167,7 +202,7 @@ pub(crate) trait NodeExt<'dom> {
fn as_iframe(&self) -> Option<(PipelineId, BrowsingContextId)>;
fn as_video(&self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)>;
fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
- fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues>;
+ fn style(&self, context: &SharedStyleContext) -> ServoArc<ComputedValues>;
fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
fn layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
@@ -180,6 +215,8 @@ pub(crate) trait NodeExt<'dom> {
fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
fn invalidate_cached_fragment(&self);
+
+ fn repair_style(&self, context: &SharedStyleContext);
}
impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
@@ -253,8 +290,8 @@ impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
.map(|string| string.to_owned())
}
- fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues> {
- self.to_threadsafe().style(context.shared_context())
+ fn style(&self, context: &SharedStyleContext) -> ServoArc<ComputedValues> {
+ self.to_threadsafe().style(context)
}
fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
@@ -339,4 +376,30 @@ impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
})
.unwrap_or_default()
}
+
+ fn repair_style(&self, context: &SharedStyleContext) {
+ let data = self.layout_data_mut();
+ if let Some(layout_object) = &*data.self_box.borrow() {
+ let style = self.to_threadsafe().style(context);
+ layout_object.repair_style(context, self, &style);
+ }
+
+ if let Some(layout_object) = &*data.pseudo_before_box.borrow() {
+ if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::Before) {
+ layout_object.repair_style(context, self, &node.style(context));
+ }
+ }
+
+ if let Some(layout_object) = &*data.pseudo_after_box.borrow() {
+ if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::After) {
+ layout_object.repair_style(context, self, &node.style(context));
+ }
+ }
+
+ if let Some(layout_object) = &*data.pseudo_marker_box.borrow() {
+ if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::Marker) {
+ layout_object.repair_style(context, self, &node.style(context));
+ }
+ }
+ }
}
diff --git a/components/layout/dom_traversal.rs b/components/layout/dom_traversal.rs
index a75d699a1b3..0201d72dbe2 100644
--- a/components/layout/dom_traversal.rs
+++ b/components/layout/dom_traversal.rs
@@ -23,6 +23,7 @@ use style::values::specified::Quotes;
use crate::context::LayoutContext;
use crate::dom::{BoxSlot, LayoutBox, NodeExt};
+use crate::flow::inline::SharedInlineStyles;
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag};
use crate::quotes::quotes_for_lang;
use crate::replaced::ReplacedContents;
@@ -185,6 +186,12 @@ pub(super) trait TraversalHandler<'dom> {
contents: Contents,
box_slot: BoxSlot<'dom>,
);
+
+ /// Notify the handler that we are about to recurse into a `display: contents` element.
+ fn enter_display_contents(&mut self, _: SharedInlineStyles) {}
+
+ /// Notify the handler that we have finished a `display: contents` element.
+ fn leave_display_contents(&mut self) {}
}
fn traverse_children_of<'dom>(
@@ -205,7 +212,10 @@ fn traverse_children_of<'dom>(
);
if is_text_input_element || is_textarea_element {
- let info = NodeAndStyleInfo::new(parent_element, parent_element.style(context));
+ let info = NodeAndStyleInfo::new(
+ parent_element,
+ parent_element.style(context.shared_context()),
+ );
let node_text_content = parent_element.to_threadsafe().node_text_content();
if node_text_content.is_empty() {
// The addition of zero-width space here forces the text input to have an inline formatting
@@ -224,7 +234,7 @@ fn traverse_children_of<'dom>(
if !is_text_input_element && !is_textarea_element {
for child in iter_child_nodes(parent_element) {
if child.is_text_node() {
- let info = NodeAndStyleInfo::new(child, child.style(context));
+ let info = NodeAndStyleInfo::new(child, child.style(context.shared_context()));
handler.handle_text(&info, child.to_threadsafe().node_text_content());
} else if child.is_element() {
traverse_element(child, context, handler);
@@ -245,7 +255,7 @@ fn traverse_element<'dom>(
element.unset_pseudo_element_box(PseudoElement::Marker);
let replaced = ReplacedContents::for_element(element, context);
- let style = element.style(context);
+ let style = element.style(context.shared_context());
match Display::from(style.get_box().display) {
Display::None => element.unset_all_boxes(),
Display::Contents => {
@@ -254,8 +264,15 @@ fn traverse_element<'dom>(
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
element.unset_all_boxes()
} else {
- element.element_box_slot().set(LayoutBox::DisplayContents);
- traverse_children_of(element, context, handler)
+ let shared_inline_styles: SharedInlineStyles =
+ (&NodeAndStyleInfo::new(element, style)).into();
+ element
+ .element_box_slot()
+ .set(LayoutBox::DisplayContents(shared_inline_styles.clone()));
+
+ handler.enter_display_contents(shared_inline_styles);
+ traverse_children_of(element, context, handler);
+ handler.leave_display_contents();
}
},
Display::GeneratingBox(display) => {
@@ -308,8 +325,12 @@ fn traverse_eager_pseudo_element<'dom>(
Display::Contents => {
let items = generate_pseudo_element_content(&info.style, node, context);
let box_slot = node.pseudo_element_box_slot(pseudo_element_type);
- box_slot.set(LayoutBox::DisplayContents);
+ let shared_inline_styles: SharedInlineStyles = (&info).into();
+ box_slot.set(LayoutBox::DisplayContents(shared_inline_styles.clone()));
+
+ handler.enter_display_contents(shared_inline_styles);
traverse_pseudo_element_contents(&info, context, handler, items);
+ handler.leave_display_contents();
},
Display::GeneratingBox(display) => {
let items = generate_pseudo_element_content(&info.style, node, context);
diff --git a/components/layout/flexbox/layout.rs b/components/layout/flexbox/layout.rs
index e69b792e272..3ddbb71ba89 100644
--- a/components/layout/flexbox/layout.rs
+++ b/components/layout/flexbox/layout.rs
@@ -29,7 +29,9 @@ use super::{FlexContainer, FlexContainerConfig, FlexItemBox, FlexLevelBox};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentFormattingContextContents};
-use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags};
+use crate::fragment_tree::{
+ BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo,
+};
use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size, Sizes};
use crate::layout_box_base::CacheableLayoutResult;
use crate::positioned::{
@@ -142,6 +144,9 @@ struct FlexItemLayoutResult {
// Whether or not this layout had a child that dependeded on block constraints.
has_child_which_depends_on_block_constraints: bool,
+
+ // The specific layout info that this flex item had.
+ specific_layout_info: Option<SpecificLayoutInfo>,
}
impl FlexItemLayoutResult {
@@ -295,7 +300,8 @@ impl FlexLineItem<'_> {
.sides_to_flow_relative(item_margin)
.to_physical(container_writing_mode),
None, /* clearance */
- );
+ )
+ .with_specific_layout_info(self.layout_result.specific_layout_info);
// If this flex item establishes a containing block for absolutely-positioned
// descendants, then lay out any relevant absolutely-positioned children. This
@@ -1910,6 +1916,7 @@ impl FlexItem<'_> {
// size can differ from the hypothetical cross size, we should defer
// synthesizing until needed.
baseline_relative_to_margin_box: None,
+ specific_layout_info: None,
})
},
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
@@ -1944,6 +1951,7 @@ impl FlexItem<'_> {
content_block_size,
baselines: content_box_baselines,
depends_on_block_constraints,
+ specific_layout_info,
..
} = layout;
@@ -2012,6 +2020,7 @@ impl FlexItem<'_> {
containing_block_block_size: item_as_containing_block.size.block,
depends_on_block_constraints,
has_child_which_depends_on_block_constraints,
+ specific_layout_info,
})
},
}
diff --git a/components/layout/flexbox/mod.rs b/components/layout/flexbox/mod.rs
index 27b69bf289f..91a12b31812 100644
--- a/components/layout/flexbox/mod.rs
+++ b/components/layout/flexbox/mod.rs
@@ -5,6 +5,7 @@
use geom::{FlexAxis, MainStartCrossStart};
use malloc_size_of_derive::MallocSizeOf;
use servo_arc::Arc as ServoArc;
+use style::context::SharedStyleContext;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::properties::longhands::align_items::computed_value::T as AlignItems;
@@ -90,7 +91,6 @@ impl FlexContainerConfig {
pub(crate) struct FlexContainer {
children: Vec<ArcRefCell<FlexLevelBox>>,
- #[conditional_malloc_size_of]
style: ServoArc<ComputedValues>,
/// The configuration of this [`FlexContainer`].
@@ -137,6 +137,11 @@ impl FlexContainer {
config: FlexContainerConfig::new(&info.style),
}
}
+
+ pub(crate) fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
+ self.config = FlexContainerConfig::new(new_style);
+ self.style = new_style.clone();
+ }
}
#[derive(Debug, MallocSizeOf)]
@@ -146,6 +151,22 @@ pub(crate) enum FlexLevelBox {
}
impl FlexLevelBox {
+ pub(crate) fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ new_style: &ServoArc<ComputedValues>,
+ ) {
+ match self {
+ FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
+ .independent_formatting_context
+ .repair_style(context, new_style),
+ FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
+ .borrow_mut()
+ .context
+ .repair_style(context, new_style),
+ }
+ }
+
pub(crate) fn invalidate_cached_fragment(&self) {
match self {
FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs
index a50464123bc..334da8ae2b0 100644
--- a/components/layout/flow/construct.rs
+++ b/components/layout/flow/construct.rs
@@ -13,9 +13,9 @@ use style::selector_parser::PseudoElement;
use style::str::char_is_whitespace;
use super::OutsideMarker;
-use super::inline::InlineFormattingContext;
use super::inline::construct::InlineFormattingContextBuilder;
use super::inline::inline_box::InlineBox;
+use super::inline::{InlineFormattingContext, SharedInlineStyles};
use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
@@ -137,16 +137,25 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style> {
/// The propagated data to use for BoxTree construction.
propagated_data: PropagatedBoxTreeData,
- inline_formatting_context_builder: InlineFormattingContextBuilder,
+ /// The [`InlineFormattingContextBuilder`] if we have encountered any inline items,
+ /// otherwise None.
+ ///
+ /// TODO: This can be `OnceCell` once `OnceCell::get_mut_or_init` is stabilized.
+ inline_formatting_context_builder: Option<InlineFormattingContextBuilder>,
/// The [`NodeAndStyleInfo`] to use for anonymous block boxes pushed to the list of
- /// block-level boxes, lazily initialized (see `end_ongoing_inline_formatting_context`).
+ /// block-level boxes, lazily initialized.
anonymous_box_info: Option<NodeAndStyleInfo<'dom>>,
/// A collection of content that is being added to an anonymous table. This is
/// composed of any sequence of internal table elements or table captions that
/// are found outside of a table.
anonymous_table_content: Vec<AnonymousTableContent<'dom>>,
+
+ /// Any [`InlineFormattingContexts`] created need to know about the ongoing `display: contents`
+ /// ancestors that have been processed. This `Vec` allows passing those into new
+ /// [`InlineFormattingContext`]s that we create.
+ display_contents_shared_styles: Vec<SharedInlineStyles>,
}
impl BlockContainer {
@@ -194,26 +203,44 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
have_already_seen_first_line_for_text_indent: false,
anonymous_box_info: None,
anonymous_table_content: Vec::new(),
- inline_formatting_context_builder: InlineFormattingContextBuilder::new(),
+ inline_formatting_context_builder: None,
+ display_contents_shared_styles: Vec::new(),
}
}
- pub(crate) fn finish(mut self) -> BlockContainer {
- debug_assert!(
- !self
- .inline_formatting_context_builder
- .currently_processing_inline_box()
- );
+ fn currently_processing_inline_box(&self) -> bool {
+ self.inline_formatting_context_builder
+ .as_ref()
+ .is_some_and(InlineFormattingContextBuilder::currently_processing_inline_box)
+ }
- self.finish_anonymous_table_if_needed();
+ fn ensure_inline_formatting_context_builder(&mut self) -> &mut InlineFormattingContextBuilder {
+ self.inline_formatting_context_builder
+ .get_or_insert_with(|| {
+ let mut builder = InlineFormattingContextBuilder::new(self.info);
+ for shared_inline_styles in self.display_contents_shared_styles.iter() {
+ builder.enter_display_contents(shared_inline_styles.clone());
+ }
+ builder
+ })
+ }
- if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
+ fn finish_ongoing_inline_formatting_context(&mut self) -> Option<InlineFormattingContext> {
+ self.inline_formatting_context_builder.take()?.finish(
self.context,
self.propagated_data,
!self.have_already_seen_first_line_for_text_indent,
self.info.is_single_line_text_input(),
self.info.style.writing_mode.to_bidi_level(),
- ) {
+ )
+ }
+
+ pub(crate) fn finish(mut self) -> BlockContainer {
+ debug_assert!(!self.currently_processing_inline_box());
+
+ self.finish_anonymous_table_if_needed();
+
+ if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context() {
// There are two options here. This block was composed of both one or more inline formatting contexts
// and child blocks OR this block was a single inline formatting context. In the latter case, we
// just return the inline formatting context as the block itself.
@@ -251,9 +278,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
//
// Note that text content in the inline formatting context isn't enough to force the
// creation of an inline table. It requires the parent to be an inline box.
- let inline_table = self
- .inline_formatting_context_builder
- .currently_processing_inline_box();
+ let inline_table = self.currently_processing_inline_box();
// Text decorations are not propagated to atomic inline-level descendants.
// From https://drafts.csswg.org/css2/#lining-striking-props:
@@ -276,10 +301,16 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
Table::construct_anonymous(self.context, self.info, contents, propagated_data);
if inline_table {
- self.inline_formatting_context_builder.push_atomic(ifc);
+ self.ensure_inline_formatting_context_builder()
+ .push_atomic(ifc);
} else {
let table_block = ArcRefCell::new(BlockLevelBox::Independent(ifc));
- self.end_ongoing_inline_formatting_context();
+
+ if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context()
+ {
+ self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
+ }
+
self.block_level_boxes.push(BlockLevelJob {
info: table_info,
box_slot: BoxSlot::dummy(),
@@ -363,7 +394,22 @@ impl<'dom> TraversalHandler<'dom> for BlockContainerBuilder<'dom, '_> {
self.finish_anonymous_table_if_needed();
}
- self.inline_formatting_context_builder.push_text(text, info);
+ self.ensure_inline_formatting_context_builder()
+ .push_text(text, info);
+ }
+
+ fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
+ self.display_contents_shared_styles.push(styles.clone());
+ if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
+ builder.enter_display_contents(styles);
+ }
+ }
+
+ fn leave_display_contents(&mut self) {
+ self.display_contents_shared_styles.pop();
+ if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
+ builder.leave_display_contents();
+ }
}
}
@@ -433,14 +479,16 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
(display_inside, contents.is_replaced())
else {
// If this inline element is an atomic, handle it and return.
- let atomic = self.inline_formatting_context_builder.push_atomic(
+ let context = self.context;
+ let propagaged_data = self.propagated_data.without_text_decorations();
+ let atomic = self.ensure_inline_formatting_context_builder().push_atomic(
IndependentFormattingContext::construct(
- self.context,
+ context,
info,
display_inside,
contents,
// Text decorations are not propagated to atomic inline-level descendants.
- self.propagated_data.without_text_decorations(),
+ propagaged_data,
),
);
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
@@ -449,7 +497,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
// Otherwise, this is just a normal inline box. Whatever happened before, all we need to do
// before recurring is to remember this ongoing inline level box.
- self.inline_formatting_context_builder
+ self.ensure_inline_formatting_context_builder()
.start_inline_box(InlineBox::new(info), None);
if is_list_item {
@@ -476,7 +524,10 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
// `InlineFormattingContextBuilder::end_inline_box()` is returning all of those box tree
// items.
box_slot.set(LayoutBox::InlineLevel(
- self.inline_formatting_context_builder.end_inline_box(),
+ self.inline_formatting_context_builder
+ .as_mut()
+ .expect("Should be building an InlineFormattingContext")
+ .end_inline_box(),
));
}
@@ -495,12 +546,15 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
// that we want to have after we push the block below.
if let Some(inline_formatting_context) = self
.inline_formatting_context_builder
- .split_around_block_and_finish(
- self.context,
- self.propagated_data,
- !self.have_already_seen_first_line_for_text_indent,
- self.info.style.writing_mode.to_bidi_level(),
- )
+ .as_mut()
+ .and_then(|builder| {
+ builder.split_around_block_and_finish(
+ self.context,
+ self.propagated_data,
+ !self.have_already_seen_first_line_for_text_indent,
+ self.info.style.writing_mode.to_bidi_level(),
+ )
+ })
{
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
}
@@ -555,17 +609,18 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
contents: Contents,
box_slot: BoxSlot<'dom>,
) {
- if !self.inline_formatting_context_builder.is_empty() {
- let inline_level_box = self
- .inline_formatting_context_builder
- .push_absolutely_positioned_box(AbsolutelyPositionedBox::construct(
- self.context,
- info,
- display_inside,
- contents,
- ));
- box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
- return;
+ if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
+ if !builder.is_empty() {
+ let inline_level_box =
+ builder.push_absolutely_positioned_box(AbsolutelyPositionedBox::construct(
+ self.context,
+ info,
+ display_inside,
+ contents,
+ ));
+ box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
+ return;
+ }
}
let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
@@ -587,18 +642,18 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
contents: Contents,
box_slot: BoxSlot<'dom>,
) {
- if !self.inline_formatting_context_builder.is_empty() {
- let inline_level_box =
- self.inline_formatting_context_builder
- .push_float_box(FloatBox::construct(
- self.context,
- info,
- display_inside,
- contents,
- self.propagated_data,
- ));
- box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
- return;
+ if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
+ if !builder.is_empty() {
+ let inline_level_box = builder.push_float_box(FloatBox::construct(
+ self.context,
+ info,
+ display_inside,
+ contents,
+ self.propagated_data,
+ ));
+ box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
+ return;
+ }
}
let kind = BlockLevelCreator::OutOfFlowFloatBox {
@@ -613,18 +668,6 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
});
}
- fn end_ongoing_inline_formatting_context(&mut self) {
- if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
- self.context,
- self.propagated_data,
- !self.have_already_seen_first_line_for_text_indent,
- self.info.is_single_line_text_input(),
- self.info.style.writing_mode.to_bidi_level(),
- ) {
- self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
- }
- }
-
fn push_block_level_job_for_inline_formatting_context(
&mut self,
inline_formatting_context: InlineFormattingContext,
diff --git a/components/layout/flow/inline/construct.rs b/components/layout/flow/inline/construct.rs
index 74b0cf4ea7d..a99de1679a4 100644
--- a/components/layout/flow/inline/construct.rs
+++ b/components/layout/flow/inline/construct.rs
@@ -7,13 +7,15 @@ use std::char::{ToLowercase, ToUppercase};
use icu_segmenter::WordSegmenter;
use itertools::izip;
-use servo_arc::Arc;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
use style::values::specified::text::TextTransformCase;
use unicode_bidi::Level;
use super::text_run::TextRun;
-use super::{InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem};
+use super::{
+ InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem,
+ SharedInlineStyles,
+};
use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
@@ -25,6 +27,12 @@ use crate::style_ext::ComputedValuesExt;
#[derive(Default)]
pub(crate) struct InlineFormattingContextBuilder {
+ /// A stack of [`SharedInlineStyles`] including one for the root, one for each inline box on the
+ /// inline box stack, and importantly, one for every `display: contents` element that we are
+ /// currently processing. Normally `display: contents` elements don't affect the structure of
+ /// the [`InlineFormattingContext`], but the styles they provide do style their children.
+ shared_inline_styles_stack: Vec<SharedInlineStyles>,
+
/// The collection of text strings that make up this [`InlineFormattingContext`] under
/// construction.
pub text_segments: Vec<String>,
@@ -63,7 +71,7 @@ pub(crate) struct InlineFormattingContextBuilder {
/// The traversal is at all times as deep in the tree as this stack is,
/// which is why the code doesn't need to keep track of the actual
/// container root (see `handle_inline_level_element`).
- ///
+ //_
/// When an inline box ends, it's removed from this stack.
inline_box_stack: Vec<InlineBoxIdentifier>,
@@ -83,10 +91,17 @@ pub(crate) struct InlineFormattingContextBuilder {
}
impl InlineFormattingContextBuilder {
- pub(crate) fn new() -> Self {
- // For the purposes of `text-transform: capitalize` the start of the IFC is a word boundary.
+ pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
+ Self::new_for_shared_styles(vec![info.into()])
+ }
+
+ pub(crate) fn new_for_shared_styles(
+ shared_inline_styles_stack: Vec<SharedInlineStyles>,
+ ) -> Self {
Self {
+ // For the purposes of `text-transform: capitalize` the start of the IFC is a word boundary.
on_word_boundary: true,
+ shared_inline_styles_stack,
..Default::default()
}
}
@@ -100,6 +115,13 @@ impl InlineFormattingContextBuilder {
self.current_text_offset += string_to_push.len();
}
+ fn shared_inline_styles(&self) -> SharedInlineStyles {
+ self.shared_inline_styles_stack
+ .last()
+ .expect("Should always have at least one SharedInlineStyles")
+ .clone()
+ }
+
/// Return true if this [`InlineFormattingContextBuilder`] is empty for the purposes of ignoring
/// during box tree construction. An IFC is empty if it only contains TextRuns with
/// completely collapsible whitespace. When that happens it can be ignored completely.
@@ -135,7 +157,7 @@ impl InlineFormattingContextBuilder {
independent_formatting_context: IndependentFormattingContext,
) -> ArcRefCell<InlineItem> {
let inline_level_box = ArcRefCell::new(InlineItem::Atomic(
- Arc::new(independent_formatting_context),
+ ArcRefCell::new(independent_formatting_context),
self.current_text_offset,
Level::ltr(), /* This will be assigned later if necessary. */
));
@@ -166,7 +188,8 @@ impl InlineFormattingContextBuilder {
}
pub(crate) fn push_float_box(&mut self, float_box: FloatBox) -> ArcRefCell<InlineItem> {
- let inline_level_box = ArcRefCell::new(InlineItem::OutOfFlowFloatBox(Arc::new(float_box)));
+ let inline_level_box =
+ ArcRefCell::new(InlineItem::OutOfFlowFloatBox(ArcRefCell::new(float_box)));
self.inline_items.push(inline_level_box.clone());
self.contains_floats = true;
inline_level_box
@@ -179,6 +202,14 @@ impl InlineFormattingContextBuilder {
) {
self.push_control_character_string(inline_box.base.style.bidi_control_chars().0);
+ // Don't push a `SharedInlineStyles` if we are pushing this box when splitting
+ // an IFC for a block-in-inline split. Shared styles are pushed as part of setting
+ // up the second split of the IFC.
+ if inline_box.is_first_split {
+ self.shared_inline_styles_stack
+ .push(inline_box.shared_inline_styles.clone());
+ }
+
let (identifier, inline_box) = self.inline_boxes.start_inline_box(inline_box);
let inline_level_box = ArcRefCell::new(InlineItem::StartInlineBox(inline_box));
self.inline_items.push(inline_level_box.clone());
@@ -194,6 +225,8 @@ impl InlineFormattingContextBuilder {
/// a single box tree items may be produced for a single inline box when that inline
/// box is split around a block-level element.
pub(crate) fn end_inline_box(&mut self) -> Vec<ArcRefCell<InlineItem>> {
+ self.shared_inline_styles_stack.pop();
+
let (identifier, block_in_inline_splits) = self.end_inline_box_internal();
let inline_level_box = self.inline_boxes.get(&identifier);
{
@@ -272,8 +305,6 @@ impl InlineFormattingContextBuilder {
}
let selection_range = info.get_selection_range();
- let selected_style = info.get_selected_style();
-
if let Some(last_character) = new_text.chars().next_back() {
self.on_word_boundary = last_character.is_whitespace();
self.last_inline_box_ended_with_collapsible_white_space =
@@ -295,14 +326,21 @@ impl InlineFormattingContextBuilder {
.push(ArcRefCell::new(InlineItem::TextRun(ArcRefCell::new(
TextRun::new(
info.into(),
- info.style.clone(),
+ self.shared_inline_styles(),
new_range,
selection_range,
- selected_style,
),
))));
}
+ pub(crate) fn enter_display_contents(&mut self, shared_inline_styles: SharedInlineStyles) {
+ self.shared_inline_styles_stack.push(shared_inline_styles);
+ }
+
+ pub(crate) fn leave_display_contents(&mut self) {
+ self.shared_inline_styles_stack.pop();
+ }
+
pub(crate) fn split_around_block_and_finish(
&mut self,
layout_context: &LayoutContext,
@@ -318,7 +356,8 @@ impl InlineFormattingContextBuilder {
// context. It has the same inline box structure as this builder, except the boxes are
// marked as not being the first fragment. No inline content is carried over to this new
// builder.
- let mut new_builder = InlineFormattingContextBuilder::new();
+ let mut new_builder = Self::new_for_shared_styles(self.shared_inline_styles_stack.clone());
+
let block_in_inline_splits = std::mem::take(&mut self.block_in_inline_splits);
for (identifier, historical_inline_boxes) in
izip!(self.inline_box_stack.iter(), block_in_inline_splits)
@@ -356,7 +395,7 @@ impl InlineFormattingContextBuilder {
/// Finish the current inline formatting context, returning [`None`] if the context was empty.
pub(crate) fn finish(
- &mut self,
+ self,
layout_context: &LayoutContext,
propagated_data: PropagatedBoxTreeData,
has_first_formatted_line: bool,
@@ -367,11 +406,9 @@ impl InlineFormattingContextBuilder {
return None;
}
- let old_builder = std::mem::replace(self, InlineFormattingContextBuilder::new());
- assert!(old_builder.inline_box_stack.is_empty());
-
+ assert!(self.inline_box_stack.is_empty());
Some(InlineFormattingContext::new_with_builder(
- old_builder,
+ self,
layout_context,
propagated_data,
has_first_formatted_line,
diff --git a/components/layout/flow/inline/inline_box.rs b/components/layout/flow/inline/inline_box.rs
index 1c953c13074..b547f3b5935 100644
--- a/components/layout/flow/inline/inline_box.rs
+++ b/components/layout/flow/inline/inline_box.rs
@@ -7,8 +7,15 @@ use std::vec::IntoIter;
use app_units::Au;
use fonts::FontMetrics;
use malloc_size_of_derive::MallocSizeOf;
-
-use super::{InlineContainerState, InlineContainerStateFlags, inline_container_needs_strut};
+use script::layout_dom::ServoLayoutNode;
+use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
+use servo_arc::Arc as ServoArc;
+use style::properties::ComputedValues;
+
+use super::{
+ InlineContainerState, InlineContainerStateFlags, SharedInlineStyles,
+ inline_container_needs_strut,
+};
use crate::ContainingBlock;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
@@ -20,6 +27,9 @@ use crate::style_ext::{LayoutStyle, PaddingBorderMargin};
#[derive(Debug, MallocSizeOf)]
pub(crate) struct InlineBox {
pub base: LayoutBoxBase,
+ /// The [`SharedInlineStyles`] for this [`InlineBox`] that are used to share styles
+ /// with all [`super::TextRun`] children.
+ pub(super) shared_inline_styles: SharedInlineStyles,
/// The identifier of this inline box in the containing [`super::InlineFormattingContext`].
pub(super) identifier: InlineBoxIdentifier,
/// Whether or not this is the first instance of an [`InlineBox`] before a possible
@@ -37,6 +47,7 @@ impl InlineBox {
pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
Self {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
+ shared_inline_styles: info.into(),
// This will be assigned later, when the box is actually added to the IFC.
identifier: InlineBoxIdentifier::default(),
is_first_split: true,
@@ -48,6 +59,7 @@ impl InlineBox {
pub(crate) fn split_around_block(&self) -> Self {
Self {
base: LayoutBoxBase::new(self.base.base_fragment_info, self.base.style.clone()),
+ shared_inline_styles: self.shared_inline_styles.clone(),
is_first_split: false,
is_last_split: false,
..*self
@@ -58,6 +70,16 @@ impl InlineBox {
pub(crate) fn layout_style(&self) -> LayoutStyle {
LayoutStyle::Default(&self.base.style)
}
+
+ pub(crate) fn repair_style(
+ &mut self,
+ node: &ServoLayoutNode,
+ new_style: &ServoArc<ComputedValues>,
+ ) {
+ self.base.repair_style(new_style);
+ *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
+ *self.shared_inline_styles.selected.borrow_mut() = node.to_threadsafe().selected_style();
+ }
}
#[derive(Debug, Default, MallocSizeOf)]
diff --git a/components/layout/flow/inline/line.rs b/components/layout/flow/inline/line.rs
index 80bab1080ed..3b92078d67d 100644
--- a/components/layout/flow/inline/line.rs
+++ b/components/layout/flow/inline/line.rs
@@ -7,7 +7,6 @@ use bitflags::bitflags;
use fonts::{ByteIndex, FontMetrics, GlyphStore};
use itertools::Either;
use range::Range;
-use servo_arc::Arc;
use style::Zero;
use style::computed_values::position::T as Position;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
@@ -21,7 +20,7 @@ use unicode_bidi::{BidiInfo, Level};
use webrender_api::FontInstanceKey;
use super::inline_box::{InlineBoxContainerState, InlineBoxIdentifier, InlineBoxTreePathToken};
-use super::{InlineFormattingContextLayout, LineBlockSizes};
+use super::{InlineFormattingContextLayout, LineBlockSizes, SharedInlineStyles};
use crate::cell::ArcRefCell;
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, TextFragment};
use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
@@ -568,7 +567,7 @@ impl LineItemLayout<'_, '_> {
self.current_state.fragments.push((
Fragment::Text(ArcRefCell::new(TextFragment {
base: text_item.base_fragment_info.into(),
- parent_style: text_item.parent_style,
+ inline_styles: text_item.inline_styles.clone(),
rect: PhysicalRect::zero(),
font_metrics: text_item.font_metrics,
font_key: text_item.font_key,
@@ -576,7 +575,6 @@ impl LineItemLayout<'_, '_> {
text_decoration_line: text_item.text_decoration_line,
justification_adjustment: self.justification_adjustment,
selection_range: text_item.selection_range,
- selected_style: text_item.selected_style,
})),
content_rect,
));
@@ -763,7 +761,7 @@ impl LineItem {
pub(super) struct TextRunLineItem {
pub base_fragment_info: BaseFragmentInfo,
- pub parent_style: Arc<ComputedValues>,
+ pub inline_styles: SharedInlineStyles,
pub text: Vec<std::sync::Arc<GlyphStore>>,
pub font_metrics: FontMetrics,
pub font_key: FontInstanceKey,
@@ -771,13 +769,16 @@ pub(super) struct TextRunLineItem {
/// The BiDi level of this [`TextRunLineItem`] to enable reordering.
pub bidi_level: Level,
pub selection_range: Option<Range<ByteIndex>>,
- pub selected_style: Arc<ComputedValues>,
}
impl TextRunLineItem {
fn trim_whitespace_at_end(&mut self, whitespace_trimmed: &mut Au) -> bool {
if matches!(
- self.parent_style.get_inherited_text().white_space_collapse,
+ self.inline_styles
+ .style
+ .borrow()
+ .get_inherited_text()
+ .white_space_collapse,
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
) {
return false;
@@ -803,7 +804,11 @@ impl TextRunLineItem {
fn trim_whitespace_at_start(&mut self, whitespace_trimmed: &mut Au) -> bool {
if matches!(
- self.parent_style.get_inherited_text().white_space_collapse,
+ self.inline_styles
+ .style
+ .borrow()
+ .get_inherited_text()
+ .white_space_collapse,
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
) {
return false;
diff --git a/components/layout/flow/inline/mod.rs b/components/layout/flow/inline/mod.rs
index 2023f4e7174..7e69aa1aaae 100644
--- a/components/layout/flow/inline/mod.rs
+++ b/components/layout/flow/inline/mod.rs
@@ -90,12 +90,13 @@ use line::{
use line_breaker::LineBreaker;
use malloc_size_of_derive::MallocSizeOf;
use range::Range;
+use script::layout_dom::ServoLayoutNode;
use servo_arc::Arc;
use style::Zero;
use style::computed_values::text_wrap_mode::T as TextWrapMode;
use style::computed_values::vertical_align::T as VerticalAlign;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
-use style::context::QuirksMode;
+use style::context::{QuirksMode, SharedStyleContext};
use style::properties::ComputedValues;
use style::properties::style_structs::InheritedText;
use style::values::generics::box_::VerticalAlignKeyword;
@@ -118,6 +119,7 @@ use super::{
};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
+use crate::dom_traversal::NodeAndStyleInfo;
use crate::flow::CollapsibleWithParentStartMargin;
use crate::flow::float::{FloatBox, SequentialLayoutState};
use crate::formatting_contexts::{
@@ -131,7 +133,7 @@ use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
-use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData};
+use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData, SharedStyle};
// From gfxFontConstants.h in Firefox.
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
@@ -173,6 +175,25 @@ pub(crate) struct InlineFormattingContext {
pub(super) has_right_to_left_content: bool,
}
+/// [`TextRun`] and `TextFragment`s need a handle on their parent inline box (or inline
+/// formatting context root)'s style. In order to implement incremental layout, these are
+/// wrapped in [`SharedStyle`]. This allows updating the parent box tree element without
+/// updating every single descendant box tree node and fragment.
+#[derive(Clone, Debug, MallocSizeOf)]
+pub(crate) struct SharedInlineStyles {
+ pub style: SharedStyle,
+ pub selected: SharedStyle,
+}
+
+impl From<&NodeAndStyleInfo<'_>> for SharedInlineStyles {
+ fn from(info: &NodeAndStyleInfo) -> Self {
+ Self {
+ style: SharedStyle::new(info.style.clone()),
+ selected: SharedStyle::new(info.get_selected_style()),
+ }
+ }
+}
+
/// A collection of data used to cache [`FontMetrics`] in the [`InlineFormattingContext`]
#[derive(Debug, MallocSizeOf)]
pub(crate) struct FontKeyAndMetrics {
@@ -190,15 +211,41 @@ pub(crate) enum InlineItem {
ArcRefCell<AbsolutelyPositionedBox>,
usize, /* offset_in_text */
),
- OutOfFlowFloatBox(#[conditional_malloc_size_of] Arc<FloatBox>),
+ OutOfFlowFloatBox(ArcRefCell<FloatBox>),
Atomic(
- #[conditional_malloc_size_of] Arc<IndependentFormattingContext>,
+ ArcRefCell<IndependentFormattingContext>,
usize, /* offset_in_text */
Level, /* bidi_level */
),
}
impl InlineItem {
+ pub(crate) fn repair_style(
+ &self,
+ context: &SharedStyleContext,
+ node: &ServoLayoutNode,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ match self {
+ InlineItem::StartInlineBox(inline_box) => {
+ inline_box.borrow_mut().repair_style(node, new_style);
+ },
+ InlineItem::EndInlineBox => {},
+ // TextRun holds a handle the `InlineSharedStyles` which is updated when repairing inline box
+ // and `display: contents` styles.
+ InlineItem::TextRun(..) => {},
+ InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => positioned_box
+ .borrow_mut()
+ .context
+ .repair_style(context, new_style),
+ InlineItem::OutOfFlowFloatBox(float_box) => float_box
+ .borrow_mut()
+ .contents
+ .repair_style(context, new_style),
+ InlineItem::Atomic(atomic, ..) => atomic.borrow_mut().repair_style(context, new_style),
+ }
+ }
+
pub(crate) fn invalidate_cached_fragment(&self) {
match self {
InlineItem::StartInlineBox(inline_box) => {
@@ -212,11 +259,14 @@ impl InlineItem {
.base
.invalidate_cached_fragment();
},
- InlineItem::OutOfFlowFloatBox(float_box) => {
- float_box.contents.base.invalidate_cached_fragment()
- },
+ InlineItem::OutOfFlowFloatBox(float_box) => float_box
+ .borrow()
+ .contents
+ .base
+ .invalidate_cached_fragment(),
InlineItem::Atomic(independent_formatting_context, ..) => {
independent_formatting_context
+ .borrow()
.base
.invalidate_cached_fragment();
},
@@ -232,9 +282,11 @@ impl InlineItem {
InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
positioned_box.borrow().context.base.fragments()
},
- InlineItem::OutOfFlowFloatBox(float_box) => float_box.contents.base.fragments(),
+ InlineItem::OutOfFlowFloatBox(float_box) => {
+ float_box.borrow().contents.base.fragments()
+ },
InlineItem::Atomic(independent_formatting_context, ..) => {
- independent_formatting_context.base.fragments()
+ independent_formatting_context.borrow().base.fragments()
},
}
}
@@ -958,6 +1010,7 @@ impl InlineFormattingContextLayout<'_> {
.as_physical(Some(self.containing_block));
self.fragments
.push(Fragment::Positioning(PositioningFragment::new_anonymous(
+ self.root_nesting_level.style.clone(),
physical_line_rect,
fragments,
)));
@@ -1313,7 +1366,7 @@ impl InlineFormattingContextLayout<'_> {
) {
let inline_advance = glyph_store.total_advance();
let flags = if glyph_store.is_whitespace() {
- SegmentContentFlags::from(text_run.parent_style.get_inherited_text())
+ SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
} else {
SegmentContentFlags::empty()
};
@@ -1398,13 +1451,12 @@ impl InlineFormattingContextLayout<'_> {
TextRunLineItem {
text: vec![glyph_store],
base_fragment_info: text_run.base_fragment_info,
- parent_style: text_run.parent_style.clone(),
+ inline_styles: text_run.inline_styles.clone(),
font_metrics,
font_key: ifc_font_info.key,
text_decoration_line: self.current_inline_container_state().text_decoration_line,
bidi_level,
selection_range,
- selected_style: text_run.selected_style.clone(),
},
));
}
@@ -1751,7 +1803,7 @@ impl InlineFormattingContext {
InlineItem::EndInlineBox => layout.finish_inline_box(),
InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout),
InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => {
- atomic_formatting_context.layout_into_line_items(
+ atomic_formatting_context.borrow().layout_into_line_items(
&mut layout,
*offset_in_text,
*bidi_level,
@@ -1766,7 +1818,7 @@ impl InlineFormattingContext {
));
},
InlineItem::OutOfFlowFloatBox(float_box) => {
- float_box.layout_into_line_items(&mut layout);
+ float_box.borrow().layout_into_line_items(&mut layout);
},
}
}
@@ -2363,8 +2415,9 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
},
InlineItem::TextRun(text_run) => {
let text_run = &*text_run.borrow();
+ let parent_style = text_run.inline_styles.style.borrow();
for segment in text_run.shaped_text.iter() {
- let style_text = text_run.parent_style.get_inherited_text();
+ let style_text = parent_style.get_inherited_text();
let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
// TODO: This should take account whether or not the first and last character prevent
@@ -2428,7 +2481,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
let InlineContentSizesResult {
sizes: outer,
depends_on_block_constraints,
- } = atomic.outer_inline_content_sizes(
+ } = atomic.borrow().outer_inline_content_sizes(
self.layout_context,
&self.constraint_space.into(),
&LogicalVec2::zero(),
diff --git a/components/layout/flow/inline/text_run.rs b/components/layout/flow/inline/text_run.rs
index 0d0c6398017..591c7b9b5e2 100644
--- a/components/layout/flow/inline/text_run.rs
+++ b/components/layout/flow/inline/text_run.rs
@@ -26,7 +26,7 @@ use unicode_script::Script;
use xi_unicode::linebreak_property;
use super::line_breaker::LineBreaker;
-use super::{FontKeyAndMetrics, InlineFormattingContextLayout};
+use super::{FontKeyAndMetrics, InlineFormattingContextLayout, SharedInlineStyles};
use crate::fragment_tree::BaseFragmentInfo;
// These constants are the xi-unicode line breaking classes that are defined in
@@ -37,22 +37,6 @@ pub(crate) const XI_LINE_BREAKING_CLASS_ZW: u8 = 28;
pub(crate) const XI_LINE_BREAKING_CLASS_WJ: u8 = 30;
pub(crate) const XI_LINE_BREAKING_CLASS_ZWJ: u8 = 42;
-/// <https://www.w3.org/TR/css-display-3/#css-text-run>
-#[derive(Debug, MallocSizeOf)]
-pub(crate) struct TextRun {
- pub base_fragment_info: BaseFragmentInfo,
- #[conditional_malloc_size_of]
- pub parent_style: Arc<ComputedValues>,
- pub text_range: Range<usize>,
-
- /// The text of this [`TextRun`] with a font selected, broken into unbreakable
- /// segments, and shaped.
- pub shaped_text: Vec<TextRunSegment>,
- pub selection_range: Option<ServoRange<ByteIndex>>,
- #[conditional_malloc_size_of]
- pub selected_style: Arc<ComputedValues>,
-}
-
// There are two reasons why we might want to break at the start:
//
// 1. The line breaker told us that a break was necessary between two separate
@@ -334,21 +318,49 @@ impl TextRunSegment {
}
}
+/// A single [`TextRun`] for the box tree. These are all descendants of
+/// [`super::InlineBox`] or the root of the [`super::InlineFormattingContext`]. During
+/// box tree construction, text is split into [`TextRun`]s based on their font, script,
+/// etc. When these are created text is already shaped.
+///
+/// <https://www.w3.org/TR/css-display-3/#css-text-run>
+#[derive(Debug, MallocSizeOf)]
+pub(crate) struct TextRun {
+ /// The [`BaseFragmentInfo`] for this [`TextRun`]. Usually this comes from the
+ /// original text node in the DOM for the text.
+ pub base_fragment_info: BaseFragmentInfo,
+
+ /// The [`crate::SharedStyle`] from this [`TextRun`]s parent element. This is
+ /// shared so that incremental layout can simply update the parent element and
+ /// this [`TextRun`] will be updated automatically.
+ pub inline_styles: SharedInlineStyles,
+
+ /// The range of text in [`super::InlineFormattingContext::text_content`] of the
+ /// [`super::InlineFormattingContext`] that owns this [`TextRun`]. These are UTF-8 offsets.
+ pub text_range: Range<usize>,
+
+ /// The text of this [`TextRun`] with a font selected, broken into unbreakable
+ /// segments, and shaped.
+ pub shaped_text: Vec<TextRunSegment>,
+
+ /// The selection range for the DOM text node that originated this [`TextRun`]. This
+ /// comes directly from the DOM.
+ pub selection_range: Option<ServoRange<ByteIndex>>,
+}
+
impl TextRun {
pub(crate) fn new(
base_fragment_info: BaseFragmentInfo,
- parent_style: Arc<ComputedValues>,
+ inline_styles: SharedInlineStyles,
text_range: Range<usize>,
selection_range: Option<ServoRange<ByteIndex>>,
- selected_style: Arc<ComputedValues>,
) -> Self {
Self {
base_fragment_info,
- parent_style,
+ inline_styles,
text_range,
shaped_text: Vec::new(),
selection_range,
- selected_style,
}
}
@@ -360,11 +372,12 @@ impl TextRun {
font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo,
) {
- let inherited_text_style = self.parent_style.get_inherited_text().clone();
+ let parent_style = self.inline_styles.style.borrow().clone();
+ let inherited_text_style = parent_style.get_inherited_text().clone();
let letter_spacing = inherited_text_style
.letter_spacing
.0
- .resolve(self.parent_style.clone_font().font_size.computed_size());
+ .resolve(parent_style.clone_font().font_size.computed_size());
let letter_spacing = if letter_spacing.px() != 0. {
Some(app_units::Au::from(letter_spacing))
} else {
@@ -384,7 +397,13 @@ impl TextRun {
let style_word_spacing: Option<Au> = specified_word_spacing.to_length().map(|l| l.into());
let segments = self
- .segment_text_by_font(formatting_context_text, font_context, font_cache, bidi_info)
+ .segment_text_by_font(
+ formatting_context_text,
+ font_context,
+ font_cache,
+ bidi_info,
+ &parent_style,
+ )
.into_iter()
.map(|(mut segment, font)| {
let word_spacing = style_word_spacing.unwrap_or_else(|| {
@@ -407,7 +426,7 @@ impl TextRun {
};
segment.shape_text(
- &self.parent_style,
+ &parent_style,
formatting_context_text,
linebreaker,
&shaping_options,
@@ -430,8 +449,9 @@ impl TextRun {
font_context: &FontContext,
font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo,
+ parent_style: &Arc<ComputedValues>,
) -> Vec<(TextRunSegment, FontRef)> {
- let font_group = font_context.font_group(self.parent_style.clone_font());
+ let font_group = font_context.font_group(parent_style.clone_font());
let mut current: Option<(TextRunSegment, FontRef)> = None;
let mut results = Vec::new();
diff --git a/components/layout/flow/mod.rs b/components/layout/flow/mod.rs
index e23193f3904..6adb63153d6 100644
--- a/components/layout/flow/mod.rs
+++ b/components/layout/flow/mod.rs
@@ -9,9 +9,11 @@ use app_units::{Au, MAX_AU};
use inline::InlineFormattingContext;
use malloc_size_of_derive::MallocSizeOf;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
+use script::layout_dom::ServoLayoutNode;
use servo_arc::Arc;
use style::Zero;
use style::computed_values::clear::T as StyleClear;
+use style::context::SharedStyleContext;
use style::logical_geometry::Direction;
use style::properties::ComputedValues;
use style::servo::selector_parser::PseudoElement;
@@ -21,6 +23,7 @@ use style::values::specified::{Display, TextAlignKeyword};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
+use crate::dom::NodeExt;
use crate::flow::float::{
Clear, ContainingBlockPositionInfo, FloatBox, FloatSide, PlacementAmongFloats,
SequentialLayoutState,
@@ -91,6 +94,36 @@ pub(crate) enum BlockLevelBox {
}
impl BlockLevelBox {
+ pub(crate) fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ node: &ServoLayoutNode,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ self.with_base_mut(|base| {
+ base.repair_style(new_style);
+ });
+
+ match self {
+ BlockLevelBox::Independent(independent_formatting_context) => {
+ independent_formatting_context.repair_style(context, new_style)
+ },
+ BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
+ .borrow_mut()
+ .context
+ .repair_style(context, new_style),
+ BlockLevelBox::OutOfFlowFloatBox(float_box) => {
+ float_box.contents.repair_style(context, new_style)
+ },
+ BlockLevelBox::OutsideMarker(outside_marker) => {
+ outside_marker.repair_style(context, node, new_style)
+ },
+ BlockLevelBox::SameFormattingContextBlock { base, .. } => {
+ base.repair_style(new_style);
+ },
+ }
+ }
+
pub(crate) fn invalidate_cached_fragment(&self) {
self.with_base(LayoutBoxBase::invalidate_cached_fragment);
}
@@ -113,6 +146,20 @@ impl BlockLevelBox {
}
}
+ pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T {
+ match self {
+ BlockLevelBox::Independent(independent_formatting_context) => {
+ callback(&mut independent_formatting_context.base)
+ },
+ BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
+ callback(&mut positioned_box.borrow_mut().context.base)
+ },
+ BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&mut float_box.contents.base),
+ BlockLevelBox::OutsideMarker(outside_marker) => callback(&mut outside_marker.base),
+ BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
+ }
+ }
+
fn contains_floats(&self) -> bool {
match self {
BlockLevelBox::SameFormattingContextBlock {
@@ -249,7 +296,6 @@ pub(crate) struct CollapsibleWithParentStartMargin(bool);
/// for a list that has `list-style-position: outside`.
#[derive(Debug, MallocSizeOf)]
pub(crate) struct OutsideMarker {
- #[conditional_malloc_size_of]
pub list_item_style: Arc<ComputedValues>,
pub base: LayoutBoxBase,
pub block_container: BlockContainer,
@@ -361,6 +407,16 @@ impl OutsideMarker {
None,
)))
}
+
+ fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ node: &ServoLayoutNode,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ self.list_item_style = node.style(context);
+ self.base.repair_style(new_style);
+ }
}
impl BlockFormattingContext {
diff --git a/components/layout/flow/root.rs b/components/layout/flow/root.rs
index ec85f3574dc..a37db54065d 100644
--- a/components/layout/flow/root.rs
+++ b/components/layout/flow/root.rs
@@ -59,7 +59,7 @@ impl BoxTree {
// > none, user agents must instead apply the overflow-* values of the first such child
// > element to the viewport. The element from which the value is propagated must then have a
// > used overflow value of visible.
- let root_style = root_element.style(context);
+ let root_style = root_element.style(context.shared_context());
let mut viewport_overflow_x = root_style.clone_overflow_x();
let mut viewport_overflow_y = root_style.clone_overflow_y();
@@ -76,7 +76,7 @@ impl BoxTree {
continue;
}
- let style = child.style(context);
+ let style = child.style(context.shared_context());
if !style.get_box().display.is_none() {
viewport_overflow_x = style.clone_overflow_x();
viewport_overflow_y = style.clone_overflow_y();
@@ -174,7 +174,7 @@ impl BoxTree {
let update_point =
match &*AtomicRef::filter_map(layout_data.self_box.borrow(), Option::as_ref)? {
- LayoutBox::DisplayContents => return None,
+ LayoutBox::DisplayContents(..) => return None,
LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
if box_style.position.is_absolutely_positioned() =>
@@ -293,7 +293,7 @@ fn construct_for_root_element(
context: &LayoutContext,
root_element: ServoLayoutNode<'_>,
) -> Vec<ArcRefCell<BlockLevelBox>> {
- let info = NodeAndStyleInfo::new(root_element, root_element.style(context));
+ let info = NodeAndStyleInfo::new(root_element, root_element.style(context.shared_context()));
let box_style = info.style.get_box();
let display_inside = match Display::from(box_style.display) {
diff --git a/components/layout/formatting_contexts.rs b/components/layout/formatting_contexts.rs
index 04a8c60f692..d704011d0e7 100644
--- a/components/layout/formatting_contexts.rs
+++ b/components/layout/formatting_contexts.rs
@@ -6,6 +6,7 @@ use app_units::Au;
use malloc_size_of_derive::MallocSizeOf;
use script::layout_dom::ServoLayoutElement;
use servo_arc::Arc;
+use style::context::SharedStyleContext;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
@@ -217,6 +218,20 @@ impl IndependentFormattingContext {
},
}
}
+
+ pub(crate) fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ self.base.repair_style(new_style);
+ match &mut self.contents {
+ IndependentFormattingContextContents::NonReplaced(content) => {
+ content.repair_style(context, new_style);
+ },
+ IndependentFormattingContextContents::Replaced(..) => {},
+ }
+ }
}
impl IndependentNonReplacedContents {
@@ -334,6 +349,19 @@ impl IndependentNonReplacedContents {
pub(crate) fn is_table(&self) -> bool {
matches!(self, Self::Table(_))
}
+
+ fn repair_style(&mut self, context: &SharedStyleContext, new_style: &Arc<ComputedValues>) {
+ match self {
+ IndependentNonReplacedContents::Flow(..) => {},
+ IndependentNonReplacedContents::Flex(flex_container) => {
+ flex_container.repair_style(new_style)
+ },
+ IndependentNonReplacedContents::Grid(taffy_container) => {
+ taffy_container.repair_style(new_style)
+ },
+ IndependentNonReplacedContents::Table(table) => table.repair_style(context, new_style),
+ }
+ }
}
impl ComputeInlineContentSizes for IndependentNonReplacedContents {
diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs
index 596556b296c..9b96b1c4fb4 100644
--- a/components/layout/fragment_tree/box_fragment.rs
+++ b/components/layout/fragment_tree/box_fragment.rs
@@ -17,7 +17,7 @@ use style::properties::ComputedValues;
use style::values::specified::box_::DisplayOutside;
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment, FragmentFlags};
-use crate::ArcRefCell;
+use crate::SharedStyle;
use crate::display_list::ToWebRender;
use crate::formatting_contexts::Baselines;
use crate::geom::{
@@ -40,15 +40,9 @@ pub(crate) enum BackgroundMode {
/// Draw the background normally, getting information from the Fragment style.
Normal,
}
-
-#[derive(Debug, MallocSizeOf)]
-pub(crate) struct BackgroundStyle(#[conditional_malloc_size_of] pub ServoArc<ComputedValues>);
-
-pub(crate) type SharedBackgroundStyle = ArcRefCell<BackgroundStyle>;
-
#[derive(MallocSizeOf)]
pub(crate) struct ExtraBackground {
- pub style: SharedBackgroundStyle,
+ pub style: SharedStyle,
pub rect: PhysicalRect<Au>,
}
@@ -64,7 +58,6 @@ pub(crate) enum SpecificLayoutInfo {
pub(crate) struct BoxFragment {
pub base: BaseFragment,
- #[conditional_malloc_size_of]
pub style: ServoArc<ComputedValues>,
pub children: Vec<Fragment>,
diff --git a/components/layout/fragment_tree/fragment.rs b/components/layout/fragment_tree/fragment.rs
index 1c5324fa1c4..1ebc7b3c989 100644
--- a/components/layout/fragment_tree/fragment.rs
+++ b/components/layout/fragment_tree/fragment.rs
@@ -22,6 +22,7 @@ use super::{
Tag,
};
use crate::cell::ArcRefCell;
+use crate::flow::inline::SharedInlineStyles;
use crate::geom::{LogicalSides, PhysicalPoint, PhysicalRect};
use crate::style_ext::ComputedValuesExt;
@@ -64,8 +65,7 @@ pub(crate) struct CollapsedMargin {
#[derive(MallocSizeOf)]
pub(crate) struct TextFragment {
pub base: BaseFragment,
- #[conditional_malloc_size_of]
- pub parent_style: ServoArc<ComputedValues>,
+ pub inline_styles: SharedInlineStyles,
pub rect: PhysicalRect<Au>,
pub font_metrics: FontMetrics,
pub font_key: FontInstanceKey,
@@ -78,14 +78,11 @@ pub(crate) struct TextFragment {
/// Extra space to add for each justification opportunity.
pub justification_adjustment: Au,
pub selection_range: Option<ServoRange<ByteIndex>>,
- #[conditional_malloc_size_of]
- pub selected_style: ServoArc<ComputedValues>,
}
#[derive(MallocSizeOf)]
pub(crate) struct ImageFragment {
pub base: BaseFragment,
- #[conditional_malloc_size_of]
pub style: ServoArc<ComputedValues>,
pub rect: PhysicalRect<Au>,
pub clip: PhysicalRect<Au>,
@@ -97,7 +94,6 @@ pub(crate) struct IFrameFragment {
pub base: BaseFragment,
pub pipeline_id: PipelineId,
pub rect: PhysicalRect<Au>,
- #[conditional_malloc_size_of]
pub style: ServoArc<ComputedValues>,
}
@@ -308,6 +304,25 @@ impl Fragment {
_ => None,
}
}
+
+ pub(crate) fn repair_style(&self, style: &ServoArc<ComputedValues>) {
+ match self {
+ Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
+ box_fragment.borrow_mut().style = style.clone()
+ },
+ Fragment::Positioning(positioning_fragment) => {
+ positioning_fragment.borrow_mut().style = style.clone();
+ },
+ Fragment::AbsoluteOrFixedPositioned(positioned_fragment) => {
+ if let Some(ref fragment) = positioned_fragment.borrow().fragment {
+ fragment.repair_style(style);
+ }
+ },
+ Fragment::Text(..) => unreachable!("Should never try to repair style of TextFragment"),
+ Fragment::Image(image_fragment) => image_fragment.borrow_mut().style = style.clone(),
+ Fragment::IFrame(iframe_fragment) => iframe_fragment.borrow_mut().style = style.clone(),
+ }
+ }
}
impl TextFragment {
diff --git a/components/layout/fragment_tree/positioning_fragment.rs b/components/layout/fragment_tree/positioning_fragment.rs
index 0cf525a3479..e45a6137bff 100644
--- a/components/layout/fragment_tree/positioning_fragment.rs
+++ b/components/layout/fragment_tree/positioning_fragment.rs
@@ -24,9 +24,8 @@ pub(crate) struct PositioningFragment {
/// The scrollable overflow of this anonymous fragment's children.
pub scrollable_overflow: PhysicalRect<Au>,
- /// If this fragment was created with a style, the style of the fragment.
- #[conditional_malloc_size_of]
- pub style: Option<ServoArc<ComputedValues>>,
+ /// The style of the fragment.
+ pub style: ServoArc<ComputedValues>,
/// This [`PositioningFragment`]'s containing block rectangle in coordinates relative to
/// the initial containing block, but not taking into account any transforms.
@@ -34,8 +33,12 @@ pub(crate) struct PositioningFragment {
}
impl PositioningFragment {
- pub fn new_anonymous(rect: PhysicalRect<Au>, children: Vec<Fragment>) -> ArcRefCell<Self> {
- Self::new_with_base_fragment(BaseFragment::anonymous(), None, rect, children)
+ pub fn new_anonymous(
+ style: ServoArc<ComputedValues>,
+ rect: PhysicalRect<Au>,
+ children: Vec<Fragment>,
+ ) -> ArcRefCell<Self> {
+ Self::new_with_base_fragment(BaseFragment::anonymous(), style, rect, children)
}
pub fn new_empty(
@@ -43,12 +46,12 @@ impl PositioningFragment {
rect: PhysicalRect<Au>,
style: ServoArc<ComputedValues>,
) -> ArcRefCell<Self> {
- Self::new_with_base_fragment(base_fragment_info.into(), Some(style), rect, Vec::new())
+ Self::new_with_base_fragment(base_fragment_info.into(), style, rect, Vec::new())
}
fn new_with_base_fragment(
base: BaseFragment,
- style: Option<ServoArc<ComputedValues>>,
+ style: ServoArc<ComputedValues>,
rect: PhysicalRect<Au>,
children: Vec<Fragment>,
) -> ArcRefCell<Self> {
diff --git a/components/layout/layout_box_base.rs b/components/layout/layout_box_base.rs
index 71fbfdeced1..161aee0f9bb 100644
--- a/components/layout/layout_box_base.rs
+++ b/components/layout/layout_box_base.rs
@@ -27,7 +27,6 @@ use crate::{ConstraintSpace, ContainingBlockSize};
#[derive(MallocSizeOf)]
pub(crate) struct LayoutBoxBase {
pub base_fragment_info: BaseFragmentInfo,
- #[conditional_malloc_size_of]
pub style: Arc<ComputedValues>,
pub cached_inline_content_size:
AtomicRefCell<Option<Box<(SizeConstraint, InlineContentSizesResult)>>>,
@@ -90,6 +89,13 @@ impl LayoutBoxBase {
pub(crate) fn clear_fragments(&self) {
self.fragments.borrow_mut().clear();
}
+
+ pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.style = new_style.clone();
+ for fragment in self.fragments.borrow_mut().iter_mut() {
+ fragment.repair_style(new_style);
+ }
+ }
}
impl Debug for LayoutBoxBase {
diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs
index cdf76d3fed0..fcf658036b2 100644
--- a/components/layout/layout_impl.rs
+++ b/components/layout/layout_impl.rs
@@ -56,7 +56,7 @@ use style::media_queries::{Device, MediaList, MediaType};
use style::properties::style_structs::Font;
use style::properties::{ComputedValues, PropertyId};
use style::queries::values::PrefersColorScheme;
-use style::selector_parser::{PseudoElement, SnapshotMap};
+use style::selector_parser::{PseudoElement, RestyleDamage, SnapshotMap};
use style::servo::media_queries::FontMetricsProvider;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
use style::stylesheets::{
@@ -83,7 +83,7 @@ use crate::query::{
process_content_boxes_request, process_node_scroll_area_request, process_offset_parent_query,
process_resolved_font_style_query, process_resolved_style_request, process_text_index_request,
};
-use crate::traversal::RecalcStyle;
+use crate::traversal::{RecalcStyle, compute_damage_and_repair_style};
use crate::{BoxTree, FragmentTree};
// This mutex is necessary due to syncronisation issues between two different types of thread-local storage
@@ -765,6 +765,12 @@ impl LayoutThread {
driver::traverse_dom(&recalc_style_traversal, token, rayon_pool).as_node();
let root_node = root_element.as_node();
+ let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node);
+ if damage == RestyleDamage::REPAINT {
+ layout_context.style_context.stylist.rule_tree().maybe_gc();
+ return;
+ }
+
let mut box_tree = self.box_tree.borrow_mut();
let box_tree = &mut *box_tree;
let mut build_box_tree = || {
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index af7d432c4d8..cd992387277 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -38,6 +38,7 @@ pub use flow::BoxTree;
pub use fragment_tree::FragmentTree;
pub use layout_impl::LayoutFactoryImpl;
use malloc_size_of_derive::MallocSizeOf;
+use servo_arc::Arc as ServoArc;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::values::computed::TextDecorationLine;
@@ -45,6 +46,16 @@ use style::values::computed::TextDecorationLine;
use crate::geom::{LogicalVec2, SizeConstraint};
use crate::style_ext::AspectRatio;
+/// At times, a style is "owned" by more than one layout object. For example, text
+/// fragments need a handle on their parent inline box's style. In order to make
+/// incremental layout easier to implement, another layer of shared ownership is added via
+/// [`SharedStyle`]. This allows updating the style in originating layout object and
+/// having all "depdendent" objects update automatically.
+///
+/// Note that this is not a cost-free data structure, so should only be
+/// used when necessary.
+pub(crate) type SharedStyle = ArcRefCell<ServoArc<ComputedValues>>;
+
/// Represents the set of constraints that we use when computing the min-content
/// and max-content inline sizes of an element.
pub(crate) struct ConstraintSpace {
diff --git a/components/layout/positioned.rs b/components/layout/positioned.rs
index bb5386dc696..b607462d6eb 100644
--- a/components/layout/positioned.rs
+++ b/components/layout/positioned.rs
@@ -473,7 +473,7 @@ impl HoistedAbsolutelyPositionedBox {
false => shared_fragment.resolved_alignment.inline,
};
- let mut inline_axis_solver = AbsoluteAxisSolver {
+ let inline_axis_solver = AbsoluteAxisSolver {
axis: Direction::Inline,
containing_size: cbis,
padding_border_sum: pbm.padding_border_sums.inline,
@@ -496,7 +496,7 @@ impl HoistedAbsolutelyPositionedBox {
true => style.clone_align_self().0.0,
false => shared_fragment.resolved_alignment.block,
};
- let mut block_axis_solver = AbsoluteAxisSolver {
+ let block_axis_solver = AbsoluteAxisSolver {
axis: Direction::Block,
containing_size: cbbs,
padding_border_sum: pbm.padding_border_sums.block,
@@ -511,52 +511,6 @@ impl HoistedAbsolutelyPositionedBox {
is_table,
};
- if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents {
- // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
- // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
- let inset_sums = LogicalVec2 {
- inline: inline_axis_solver.inset_sum(),
- block: block_axis_solver.inset_sum(),
- };
- let automatic_size = |alignment: AlignFlags, offsets: &LogicalSides1D<_>| {
- if alignment.value() == AlignFlags::STRETCH && !offsets.either_auto() {
- Size::Stretch
- } else {
- Size::FitContent
- }
- };
- let used_size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
- containing_block,
- &style,
- context.preferred_aspect_ratio(&pbm.padding_border_sums),
- LogicalVec2 {
- inline: &inline_axis_solver.computed_sizes,
- block: &block_axis_solver.computed_sizes,
- },
- LogicalVec2 {
- inline: automatic_size(inline_alignment, &inline_axis_solver.box_offsets),
- block: automatic_size(block_alignment, &block_axis_solver.box_offsets),
- },
- pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums,
- );
- inline_axis_solver.override_size(used_size.inline);
- block_axis_solver.override_size(used_size.block);
- }
-
- // The block axis can depend on layout results, so we only solve it tentatively,
- // we may have to resolve it properly later on.
- let mut block_axis = block_axis_solver.solve_tentatively();
-
- // The inline axis can be fully resolved, computing intrinsic sizes using the
- // tentative block size.
- let mut inline_axis = inline_axis_solver.solve(Some(|| {
- let ratio = context.preferred_aspect_ratio(&pbm.padding_border_sums);
- let constraint_space = ConstraintSpace::new(block_axis.size, style.writing_mode, ratio);
- context
- .inline_content_sizes(layout_context, &constraint_space)
- .sizes
- }));
-
let mut positioning_context = PositioningContext::default();
let mut new_fragment = {
let content_size: LogicalVec2<Au>;
@@ -566,10 +520,34 @@ impl HoistedAbsolutelyPositionedBox {
IndependentFormattingContextContents::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
- content_size = LogicalVec2 {
- inline: inline_axis.size.to_definite().unwrap(),
- block: block_axis.size.to_definite().unwrap(),
+ let inset_sums = LogicalVec2 {
+ inline: inline_axis_solver.inset_sum(),
+ block: block_axis_solver.inset_sum(),
+ };
+ let automatic_size = |alignment: AlignFlags, offsets: &LogicalSides1D<_>| {
+ if alignment.value() == AlignFlags::STRETCH && !offsets.either_auto() {
+ Size::Stretch
+ } else {
+ Size::FitContent
+ }
};
+ content_size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
+ containing_block,
+ &style,
+ context.preferred_aspect_ratio(&pbm.padding_border_sums),
+ LogicalVec2 {
+ inline: &inline_axis_solver.computed_sizes,
+ block: &block_axis_solver.computed_sizes,
+ },
+ LogicalVec2 {
+ inline: automatic_size(
+ inline_alignment,
+ &inline_axis_solver.box_offsets,
+ ),
+ block: automatic_size(block_alignment, &block_axis_solver.box_offsets),
+ },
+ pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums,
+ );
fragments = replaced.make_fragments(
layout_context,
&style,
@@ -579,11 +557,26 @@ impl HoistedAbsolutelyPositionedBox {
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
- let inline_size = inline_axis.size.to_definite().unwrap();
+
+ // The block size can depend on layout results, so we only solve it extrinsically,
+ // we may have to resolve it properly later on.
+ let extrinsic_block_size = block_axis_solver.solve_size_extrinsically();
+
+ // The inline axis can be fully resolved, computing intrinsic sizes using the
+ // extrinsic block size.
+ let inline_size = inline_axis_solver.solve_size(|| {
+ let ratio = context.preferred_aspect_ratio(&pbm.padding_border_sums);
+ let constraint_space =
+ ConstraintSpace::new(extrinsic_block_size, style.writing_mode, ratio);
+ context
+ .inline_content_sizes(layout_context, &constraint_space)
+ .sizes
+ });
+
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
- block: block_axis.size,
+ block: extrinsic_block_size,
},
style: &style,
};
@@ -603,22 +596,14 @@ impl HoistedAbsolutelyPositionedBox {
false, /* depends_on_block_constraints */
);
- let inline_size = if let Some(inline_size) =
- independent_layout.content_inline_size_for_table
- {
- // Tables can become narrower than predicted due to collapsed columns,
- // so we need to solve again to update margins.
- inline_axis_solver.override_size(inline_size);
- inline_axis = inline_axis_solver.solve_tentatively();
- inline_size
- } else {
- inline_size
- };
+ // Tables can become narrower than predicted due to collapsed columns
+ let inline_size = independent_layout
+ .content_inline_size_for_table
+ .unwrap_or(inline_size);
// Now we can properly solve the block size.
- block_axis = block_axis_solver
- .solve(Some(|| independent_layout.content_block_size.into()));
- let block_size = block_axis.size.to_definite().unwrap();
+ let block_size = block_axis_solver
+ .solve_size(|| independent_layout.content_block_size.into());
content_size = LogicalVec2 {
inline: inline_size,
@@ -629,11 +614,13 @@ impl HoistedAbsolutelyPositionedBox {
},
};
+ let inline_margins = inline_axis_solver.solve_margins(content_size.inline);
+ let block_margins = block_axis_solver.solve_margins(content_size.block);
let margin = LogicalSides {
- inline_start: inline_axis.margin_start,
- inline_end: inline_axis.margin_end,
- block_start: block_axis.margin_start,
- block_end: block_axis.margin_end,
+ inline_start: inline_margins.start,
+ inline_end: inline_margins.end,
+ block_start: block_margins.start,
+ block_end: block_margins.end,
};
let pb = pbm.padding + pbm.border;
@@ -715,12 +702,6 @@ impl LogicalRect<Au> {
}
}
-struct AxisResult {
- size: SizeConstraint,
- margin_start: Au,
- margin_end: Au,
-}
-
struct AbsoluteAxisSolver<'a> {
axis: Direction,
containing_size: Au,
@@ -763,101 +744,77 @@ impl AbsoluteAxisSolver<'_> {
}
}
- /// This unifies some of the parts in common in:
- ///
- /// * <https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width>
- /// * <https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height>
- ///
- /// … and:
- ///
- /// * <https://drafts.csswg.org/css2/visudet.html#abs-replaced-width>
- /// * <https://drafts.csswg.org/css2/visudet.html#abs-replaced-height>
- ///
- /// In the replaced case, `size` is never `Auto`.
- fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult {
- let solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint {
- let stretch_size = stretch_size.max(Au::zero());
- if let Some(get_content_size) = get_content_size {
- SizeConstraint::Definite(self.computed_sizes.resolve(
- self.axis,
- initial_behavior,
- Au::zero,
- Some(stretch_size),
- get_content_size,
- self.is_table,
- ))
- } else {
- self.computed_sizes.resolve_extrinsic(
- initial_behavior,
- Au::zero(),
- Some(stretch_size),
- )
- }
- };
- if self.box_offsets.either_auto() {
- let margin_start = self.computed_margin_start.auto_is(Au::zero);
- let margin_end = self.computed_margin_end.auto_is(Au::zero);
- let stretch_size = self.containing_size -
+ #[inline]
+ fn automatic_size(&self) -> Size<Au> {
+ match self.alignment.value() {
+ _ if self.box_offsets.either_auto() => Size::FitContent,
+ AlignFlags::NORMAL | AlignFlags::AUTO if !self.is_table => Size::Stretch,
+ AlignFlags::STRETCH => Size::Stretch,
+ _ => Size::FitContent,
+ }
+ }
+
+ #[inline]
+ fn stretch_size(&self) -> Au {
+ Au::zero().max(
+ self.containing_size -
self.inset_sum() -
self.padding_border_sum -
- margin_start -
- margin_end;
- let size = solve_size(Size::FitContent, stretch_size);
- AxisResult {
- size,
- margin_start,
- margin_end,
- }
- } else {
- let mut free_space = self.containing_size - self.inset_sum() - self.padding_border_sum;
- let stretch_size = free_space -
self.computed_margin_start.auto_is(Au::zero) -
- self.computed_margin_end.auto_is(Au::zero);
- let initial_behavior = match self.alignment.value() {
- AlignFlags::NORMAL | AlignFlags::AUTO if !self.is_table => Size::Stretch,
- AlignFlags::STRETCH => Size::Stretch,
- _ => Size::FitContent,
- };
- let size = solve_size(initial_behavior, stretch_size);
- if let Some(used_size) = size.to_definite() {
- free_space -= used_size;
- } else {
- free_space = Au::zero();
- }
- let (margin_start, margin_end) =
- match (self.computed_margin_start, self.computed_margin_end) {
- (AuOrAuto::Auto, AuOrAuto::Auto) => {
- if self.avoid_negative_margin_start && free_space < Au::zero() {
- (Au::zero(), free_space)
- } else {
- let margin_start = free_space / 2;
- (margin_start, free_space - margin_start)
- }
- },
- (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (free_space - end, end),
- (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => {
- (start, free_space - start)
- },
- (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
- (start, end)
- },
- };
- AxisResult {
- size,
- margin_start,
- margin_end,
- }
- }
+ self.computed_margin_end.auto_is(Au::zero),
+ )
}
- fn solve_tentatively(&mut self) -> AxisResult {
- self.solve(None::<fn() -> ContentSizes>)
+ #[inline]
+ fn solve_size_extrinsically(&self) -> SizeConstraint {
+ self.computed_sizes.resolve_extrinsic(
+ self.automatic_size(),
+ Au::zero(),
+ Some(self.stretch_size()),
+ )
+ }
+
+ #[inline]
+ fn solve_size(&self, get_content_size: impl FnOnce() -> ContentSizes) -> Au {
+ self.computed_sizes.resolve(
+ self.axis,
+ self.automatic_size(),
+ Au::zero,
+ Some(self.stretch_size()),
+ get_content_size,
+ self.is_table,
+ )
}
- fn override_size(&mut self, size: Au) {
- self.computed_sizes.preferred = Size::Numeric(size);
- self.computed_sizes.min = Size::default();
- self.computed_sizes.max = Size::default();
+ fn solve_margins(&self, size: Au) -> LogicalSides1D<Au> {
+ if self.box_offsets.either_auto() {
+ LogicalSides1D::new(
+ self.computed_margin_start.auto_is(Au::zero),
+ self.computed_margin_end.auto_is(Au::zero),
+ )
+ } else {
+ let free_space =
+ self.containing_size - self.inset_sum() - self.padding_border_sum - size;
+ match (self.computed_margin_start, self.computed_margin_end) {
+ (AuOrAuto::Auto, AuOrAuto::Auto) => {
+ if self.avoid_negative_margin_start && free_space < Au::zero() {
+ LogicalSides1D::new(Au::zero(), free_space)
+ } else {
+ let margin_start = free_space / 2;
+ LogicalSides1D::new(margin_start, free_space - margin_start)
+ }
+ },
+ (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
+ LogicalSides1D::new(free_space - end, end)
+ },
+ (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => {
+ LogicalSides1D::new(start, free_space - start)
+ },
+ (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
+ LogicalSides1D::new(start, end)
+ },
+ }
+ }
}
fn origin_for_margin_box(
diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs
index 133904db7ae..0c238073df2 100644
--- a/components/layout/table/construct.rs
+++ b/components/layout/table/construct.rs
@@ -19,7 +19,6 @@ use super::{
Table, TableCaption, TableLevelBox, TableSlot, TableSlotCell, TableSlotCoordinates,
TableSlotOffset, TableTrack, TableTrackGroup, TableTrackGroupType,
};
-use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::dom::{BoxSlot, LayoutBox};
@@ -29,9 +28,10 @@ use crate::formatting_contexts::{
IndependentFormattingContext, IndependentFormattingContextContents,
IndependentNonReplacedContents,
};
-use crate::fragment_tree::{BackgroundStyle, BaseFragmentInfo, SharedBackgroundStyle};
+use crate::fragment_tree::BaseFragmentInfo;
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
+use crate::{PropagatedBoxTreeData, SharedStyle};
/// A reference to a slot and its coordinates in the table
#[derive(Debug)]
@@ -725,7 +725,7 @@ impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
base: LayoutBoxBase::new((&anonymous_info).into(), style.clone()),
group_index: self.current_row_group_index,
is_anonymous: true,
- shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(style)),
+ shared_background_style: SharedStyle::new(style),
}));
}
@@ -767,9 +767,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
group_type: internal.into(),
track_range: next_row_index..next_row_index,
- shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
- info.style.clone(),
- )),
+ shared_background_style: SharedStyle::new(info.style.clone()),
});
self.builder.table.row_groups.push(row_group.clone());
@@ -812,9 +810,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
group_index: self.current_row_group_index,
is_anonymous: false,
- shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
- info.style.clone(),
- )),
+ shared_background_style: SharedStyle::new(info.style.clone()),
});
self.push_table_row(row.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
@@ -860,9 +856,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
group_type: internal.into(),
track_range: first_column..self.builder.table.columns.len(),
- shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
- info.style.clone(),
- )),
+ shared_background_style: SharedStyle::new(info.style.clone()),
});
self.builder.table.column_groups.push(column_group.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
@@ -1145,9 +1139,7 @@ fn add_column(
base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()),
group_index,
is_anonymous,
- shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
- column_info.style.clone(),
- )),
+ shared_background_style: SharedStyle::new(column_info.style.clone()),
});
collection.extend(repeat(column.clone()).take(span as usize));
column
diff --git a/components/layout/table/layout.rs b/components/layout/table/layout.rs
index 00dac210625..5b7e79d7fb0 100644
--- a/components/layout/table/layout.rs
+++ b/components/layout/table/layout.rs
@@ -2867,6 +2867,7 @@ impl TableSlotCell {
block: vertical_align_offset,
};
let vertical_align_fragment = PositioningFragment::new_anonymous(
+ self.base.style.clone(),
vertical_align_fragment_rect.as_physical(None),
layout.layout.fragments,
);
diff --git a/components/layout/table/mod.rs b/components/layout/table/mod.rs
index 8e2783e2919..72b67863e7d 100644
--- a/components/layout/table/mod.rs
+++ b/components/layout/table/mod.rs
@@ -76,16 +76,20 @@ pub(crate) use construct::AnonymousTableContent;
pub use construct::TableBuilder;
use euclid::{Point2D, Size2D, UnknownUnit, Vector2D};
use malloc_size_of_derive::MallocSizeOf;
+use script::layout_dom::ServoLayoutElement;
use servo_arc::Arc;
+use style::context::SharedStyleContext;
use style::properties::ComputedValues;
use style::properties::style_structs::Font;
+use style::selector_parser::PseudoElement;
use style_traits::dom::OpaqueNode;
use super::flow::BlockFormattingContext;
+use crate::SharedStyle;
use crate::cell::ArcRefCell;
use crate::flow::BlockContainer;
use crate::formatting_contexts::IndependentFormattingContext;
-use crate::fragment_tree::{BaseFragmentInfo, Fragment, SharedBackgroundStyle};
+use crate::fragment_tree::{BaseFragmentInfo, Fragment};
use crate::geom::PhysicalVec;
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::BorderStyleColor;
@@ -98,12 +102,10 @@ pub struct Table {
/// The style of this table. These are the properties that apply to the "wrapper" ie the element
/// that contains both the grid and the captions. Not all properties are actually used on the
/// wrapper though, such as background and borders, which apply to the grid.
- #[conditional_malloc_size_of]
style: Arc<ComputedValues>,
/// The style of this table's grid. This is an anonymous style based on the table's style, but
/// eliminating all the properties handled by the "wrapper."
- #[conditional_malloc_size_of]
grid_style: Arc<ComputedValues>,
/// The [`BaseFragmentInfo`] for this table's grid. This is necessary so that when the
@@ -192,6 +194,19 @@ impl Table {
),
}
}
+
+ pub(crate) fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ self.style = new_style.clone();
+ self.grid_style = context.stylist.style_for_anonymous::<ServoLayoutElement>(
+ &context.guards,
+ &PseudoElement::ServoTableGrid,
+ new_style,
+ );
+ }
}
type TableSlotCoordinates = Point2D<usize, UnknownUnit>;
@@ -233,6 +248,10 @@ impl TableSlotCell {
pub fn node_id(&self) -> usize {
self.base.base_fragment_info.tag.map_or(0, |tag| tag.node.0)
}
+
+ fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.base.repair_style(new_style);
+ }
}
/// A single table slot. It may be an actual cell, or a reference
@@ -292,7 +311,14 @@ pub struct TableTrack {
/// A shared container for this track's style, used to share the style for the purposes
/// of drawing backgrounds in individual cells. This allows updating the style in a
/// single place and having it affect all cell `Fragment`s.
- shared_background_style: SharedBackgroundStyle,
+ shared_background_style: SharedStyle,
+}
+
+impl TableTrack {
+ fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.base.repair_style(new_style);
+ self.shared_background_style = SharedStyle::new(new_style.clone());
+ }
}
#[derive(Debug, MallocSizeOf, PartialEq)]
@@ -317,13 +343,18 @@ pub struct TableTrackGroup {
/// A shared container for this track's style, used to share the style for the purposes
/// of drawing backgrounds in individual cells. This allows updating the style in a
/// single place and having it affect all cell `Fragment`s.
- shared_background_style: SharedBackgroundStyle,
+ shared_background_style: SharedStyle,
}
impl TableTrackGroup {
pub(super) fn is_empty(&self) -> bool {
self.track_range.is_empty()
}
+
+ fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.base.repair_style(new_style);
+ self.shared_background_style = SharedStyle::new(new_style.clone());
+ }
}
#[derive(Debug, MallocSizeOf)]
@@ -390,4 +421,22 @@ impl TableLevelBox {
TableLevelBox::Track(track) => track.borrow().base.fragments(),
}
}
+
+ pub(crate) fn repair_style(
+ &self,
+ context: &SharedStyleContext<'_>,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ match self {
+ TableLevelBox::Caption(caption) => caption
+ .borrow_mut()
+ .context
+ .repair_style(context, new_style),
+ TableLevelBox::Cell(cell) => cell.borrow_mut().repair_style(new_style),
+ TableLevelBox::TrackGroup(track_group) => {
+ track_group.borrow_mut().repair_style(new_style);
+ },
+ TableLevelBox::Track(track) => track.borrow_mut().repair_style(new_style),
+ }
+ }
}
diff --git a/components/layout/taffy/mod.rs b/components/layout/taffy/mod.rs
index 50873fc3e66..ba80824fa99 100644
--- a/components/layout/taffy/mod.rs
+++ b/components/layout/taffy/mod.rs
@@ -8,6 +8,7 @@ use std::fmt;
use app_units::Au;
use malloc_size_of_derive::MallocSizeOf;
use servo_arc::Arc;
+use style::context::SharedStyleContext;
use style::properties::ComputedValues;
use stylo_taffy::TaffyStyloStyle;
@@ -24,7 +25,6 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
#[derive(Debug, MallocSizeOf)]
pub(crate) struct TaffyContainer {
children: Vec<ArcRefCell<TaffyItemBox>>,
- #[conditional_malloc_size_of]
style: Arc<ComputedValues>,
}
@@ -69,6 +69,10 @@ impl TaffyContainer {
style: info.style.clone(),
}
}
+
+ pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.style = new_style.clone();
+ }
}
#[derive(MallocSizeOf)]
@@ -76,7 +80,6 @@ pub(crate) struct TaffyItemBox {
pub(crate) taffy_layout: taffy::Layout,
pub(crate) child_fragments: Vec<Fragment>,
pub(crate) positioning_context: PositioningContext,
- #[conditional_malloc_size_of]
pub(crate) style: Arc<ComputedValues>,
pub(crate) taffy_level_box: TaffyItemBoxInner,
}
@@ -145,6 +148,23 @@ impl TaffyItemBox {
},
}
}
+
+ pub(crate) fn repair_style(
+ &mut self,
+ context: &SharedStyleContext,
+ new_style: &Arc<ComputedValues>,
+ ) {
+ self.style = new_style.clone();
+ match &mut self.taffy_level_box {
+ TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
+ independent_formatting_context.repair_style(context, new_style)
+ },
+ TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
+ .borrow_mut()
+ .context
+ .repair_style(context, new_style),
+ }
+ }
}
/// Details from Taffy grid layout that will be stored
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index bf60c41d6ba..17c3d0b1c20 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -2,14 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use script::layout_dom::ServoLayoutNode;
use script_layout_interface::wrapper_traits::LayoutNode;
use style::context::{SharedStyleContext, StyleContext};
use style::data::ElementData;
use style::dom::{NodeInfo, TElement, TNode};
+use style::selector_parser::RestyleDamage;
use style::traversal::{DomTraversal, PerLevelTraversalData, recalc_style_at};
+use style::values::computed::Display;
use crate::context::LayoutContext;
-use crate::dom::DOMLayoutData;
+use crate::dom::{DOMLayoutData, NodeExt};
+use crate::dom_traversal::iter_child_nodes;
pub struct RecalcStyle<'a> {
context: &'a LayoutContext<'a>,
@@ -40,14 +44,33 @@ where
) where
F: FnMut(E::ConcreteNode),
{
+ if node.is_text_node() {
+ return;
+ }
+
+ let had_style_data = node.style_data().is_some();
unsafe {
node.initialize_style_and_layout_data::<DOMLayoutData>();
- if !node.is_text_node() {
- let el = node.as_element().unwrap();
- let mut data = el.mutate_data().unwrap();
- recalc_style_at(self, traversal_data, context, el, &mut data, note_child);
- el.unset_dirty_descendants();
- }
+ }
+
+ let element = node.as_element().unwrap();
+ let mut element_data = element.mutate_data().unwrap();
+
+ if !had_style_data {
+ element_data.damage = RestyleDamage::reconstruct();
+ }
+
+ recalc_style_at(
+ self,
+ traversal_data,
+ context,
+ element,
+ &mut element_data,
+ note_child,
+ );
+
+ unsafe {
+ element.unset_dirty_descendants();
}
}
@@ -68,3 +91,48 @@ where
&self.context.style_context
}
}
+
+pub(crate) fn compute_damage_and_repair_style(
+ context: &SharedStyleContext,
+ node: ServoLayoutNode<'_>,
+) -> RestyleDamage {
+ compute_damage_and_repair_style_inner(context, node, RestyleDamage::empty())
+}
+
+pub(crate) fn compute_damage_and_repair_style_inner(
+ context: &SharedStyleContext,
+ node: ServoLayoutNode<'_>,
+ parent_restyle_damage: RestyleDamage,
+) -> RestyleDamage {
+ let original_damage;
+ let damage = {
+ let mut element_data = node
+ .style_data()
+ .expect("Should not run `compute_damage` before styling.")
+ .element_data
+ .borrow_mut();
+
+ if let Some(ref style) = element_data.styles.primary {
+ if style.get_box().display == Display::None {
+ return parent_restyle_damage;
+ }
+ }
+
+ original_damage = std::mem::take(&mut element_data.damage);
+ element_data.damage |= parent_restyle_damage;
+ element_data.damage
+ };
+
+ let mut propagated_damage = damage;
+ for child in iter_child_nodes(node) {
+ if child.is_element() {
+ propagated_damage |= compute_damage_and_repair_style_inner(context, child, damage);
+ }
+ }
+
+ if propagated_damage == RestyleDamage::REPAINT && original_damage == RestyleDamage::REPAINT {
+ node.repair_style(context);
+ }
+
+ propagated_damage
+}
diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs
index 2bdeedf986d..ae951da97e5 100644
--- a/components/malloc_size_of/lib.rs
+++ b/components/malloc_size_of/lib.rs
@@ -53,6 +53,7 @@ use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
+use style::properties::ComputedValues;
use style::values::generics::length::GenericLengthPercentageOrAuto;
pub use stylo_malloc_size_of::MallocSizeOfOps;
use uuid::Uuid;
@@ -750,6 +751,12 @@ impl<T: MallocSizeOf> MallocSizeOf for accountable_refcell::RefCell<T> {
}
}
+impl MallocSizeOf for servo_arc::Arc<ComputedValues> {
+ fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ self.conditional_size_of(ops)
+ }
+}
+
malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs
index e0867b8d07f..704901f6940 100644
--- a/components/net/http_loader.rs
+++ b/components/net/http_loader.rs
@@ -37,7 +37,7 @@ use hyper::ext::ReasonPhrase;
use hyper::header::{HeaderName, TRANSFER_ENCODING};
use hyper_serde::Serde;
use hyper_util::client::legacy::Client;
-use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use log::{debug, error, info, log_enabled, warn};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
@@ -462,7 +462,7 @@ fn auth_from_cache(
/// used to fill the body with bytes coming-in over IPC.
enum BodyChunk {
/// A chunk of bytes.
- Chunk(Vec<u8>),
+ Chunk(IpcSharedMemory),
/// Body is done.
Done,
}
@@ -489,12 +489,14 @@ enum BodySink {
}
impl BodySink {
- fn transmit_bytes(&self, bytes: Vec<u8>) {
+ fn transmit_bytes(&self, bytes: IpcSharedMemory) {
match self {
BodySink::Chunked(sender) => {
let sender = sender.clone();
HANDLE.spawn(async move {
- let _ = sender.send(Ok(Frame::data(bytes.into()))).await;
+ let _ = sender
+ .send(Ok(Frame::data(Bytes::copy_from_slice(&bytes))))
+ .await;
});
},
BodySink::Buffered(sender) => {
@@ -577,7 +579,7 @@ async fn obtain_response(
body_port,
Box::new(move |message| {
info!("Received message");
- let bytes: Vec<u8> = match message.unwrap() {
+ let bytes = match message.unwrap() {
BodyChunkResponse::Chunk(bytes) => bytes,
BodyChunkResponse::Done => {
// Step 3, abort these parallel steps.
@@ -622,8 +624,8 @@ async fn obtain_response(
let mut body = vec![];
loop {
match receiver.recv().await {
- Some(BodyChunk::Chunk(mut bytes)) => {
- body.append(&mut bytes);
+ Some(BodyChunk::Chunk(bytes)) => {
+ body.extend_from_slice(&bytes);
},
Some(BodyChunk::Done) => break,
None => warn!("Failed to read all chunks from request body."),
diff --git a/components/net/tests/http_loader.rs b/components/net/tests/http_loader.rs
index 1fc2d1b662d..b1e90276472 100644
--- a/components/net/tests/http_loader.rs
+++ b/components/net/tests/http_loader.rs
@@ -31,7 +31,7 @@ use http::{HeaderName, Method, StatusCode};
use http_body_util::combinators::BoxBody;
use hyper::body::{Body, Bytes, Incoming};
use hyper::{Request as HyperRequest, Response as HyperResponse};
-use ipc_channel::ipc;
+use ipc_channel::ipc::{self, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use net::cookie::ServoCookie;
use net::cookie_storage::CookieStorage;
@@ -100,7 +100,7 @@ pub fn expect_devtools_http_response(
}
}
-fn create_request_body_with_content(content: Vec<u8>) -> RequestBody {
+fn create_request_body_with_content(content: IpcSharedMemory) -> RequestBody {
let content_len = content.len();
let (chunk_request_sender, chunk_request_receiver) = ipc::channel().unwrap();
@@ -592,7 +592,7 @@ fn test_load_doesnt_send_request_body_on_any_redirect() {
let (pre_server, pre_url) = make_server(pre_handler);
let content = b"Body on POST!";
- let request_body = create_request_body_with_content(content.to_vec());
+ let request_body = create_request_body_with_content(IpcSharedMemory::from_bytes(content));
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer)
.body(Some(request_body))
@@ -904,7 +904,7 @@ fn test_load_sets_content_length_to_length_of_request_body() {
};
let (server, url) = make_server(handler);
- let request_body = create_request_body_with_content(content.to_vec());
+ let request_body = create_request_body_with_content(IpcSharedMemory::from_bytes(content));
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::POST)
diff --git a/components/script/body.rs b/components/script/body.rs
index 113f3ac7adb..cc7870a0845 100644
--- a/components/script/body.rs
+++ b/components/script/body.rs
@@ -7,7 +7,7 @@ use std::{ptr, slice, str};
use constellation_traits::BlobImpl;
use encoding_rs::{Encoding, UTF_8};
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use js::jsapi::{Heap, JS_ClearPendingException, JSObject, Value as JSValue};
use js::jsval::{JSVal, UndefinedValue};
@@ -73,7 +73,7 @@ struct TransmitBodyConnectHandler {
task_source: SendableTaskSource,
bytes_sender: Option<IpcSender<BodyChunkResponse>>,
control_sender: IpcSender<BodyChunkRequest>,
- in_memory: Option<Vec<u8>>,
+ in_memory: Option<IpcSharedMemory>,
in_memory_done: bool,
source: BodySource,
}
@@ -83,7 +83,7 @@ impl TransmitBodyConnectHandler {
stream: Trusted<ReadableStream>,
task_source: SendableTaskSource,
control_sender: IpcSender<BodyChunkRequest>,
- in_memory: Option<Vec<u8>>,
+ in_memory: Option<IpcSharedMemory>,
source: BodySource,
) -> TransmitBodyConnectHandler {
TransmitBodyConnectHandler {
@@ -160,7 +160,7 @@ impl TransmitBodyConnectHandler {
.bytes_sender
.as_ref()
.expect("No bytes sender to transmit source.")
- .send(BodyChunkResponse::Chunk(bytes.clone()));
+ .send(BodyChunkResponse::Chunk(bytes));
return;
}
warn!("Re-directs for file-based Blobs not supported yet.");
@@ -310,7 +310,11 @@ impl Callback for TransmitBodyPromiseHandler {
// Step 5.1 and 5.2, transmit chunk.
// Send the chunk to the body transmitter in net::http_loader::obtain_response.
// TODO: queue a fetch task on request to process request body for request.
- let _ = self.bytes_sender.send(BodyChunkResponse::Chunk(chunk));
+ let _ = self
+ .bytes_sender
+ .send(BodyChunkResponse::Chunk(IpcSharedMemory::from_bytes(
+ &chunk,
+ )));
}
}
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 52d0ca7e20c..9f1520bd085 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -8,7 +8,7 @@ use std::mem;
use devtools_traits::AttrInfo;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Namespace, Prefix, ns};
+use html5ever::{LocalName, Namespace, Prefix, local_name, ns};
use style::attr::{AttrIdentifier, AttrValue};
use style::values::GenericAtomIdent;
use stylo_atoms::Atom;
@@ -179,7 +179,7 @@ impl Attr {
assert_eq!(Some(owner), self.owner().as_deref());
owner.will_mutate_attr(self);
self.swap_value(&mut value);
- if *self.namespace() == ns!() {
+ if is_relevant_attribute(self.namespace(), self.local_name()) {
vtable_for(owner.upcast()).attribute_mutated(
self,
AttributeMutation::Set(Some(&value)),
@@ -283,3 +283,9 @@ impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> {
&self.unsafe_get().identifier.namespace.0
}
}
+
+/// A helper function to check if attribute is relevant.
+pub(crate) fn is_relevant_attribute(namespace: &Namespace, local_name: &LocalName) -> bool {
+ // <https://svgwg.org/svg2-draft/linking.html#XLinkHrefAttribute>
+ namespace == &ns!() || (namespace == &ns!(xlink) && local_name == &local_name!("href"))
+}
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index c9a49ba00c9..70638238123 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -44,7 +44,7 @@ use crate::dom::dompointreadonly::DOMPointReadOnly;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use crate::dom::readablestream::ReadableStream;
-use crate::dom::types::DOMException;
+use crate::dom::types::{DOMException, TransformStream};
use crate::dom::writablestream::WritableStream;
use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
@@ -65,6 +65,7 @@ pub(super) enum StructuredCloneTags {
ReadableStream = 0xFFFF8006,
DomException = 0xFFFF8007,
WritableStream = 0xFFFF8008,
+ TransformStream = 0xFFFF8009,
Max = 0xFFFFFFFF,
}
@@ -85,6 +86,7 @@ impl From<TransferrableInterface> for StructuredCloneTags {
TransferrableInterface::MessagePort => StructuredCloneTags::MessagePort,
TransferrableInterface::ReadableStream => StructuredCloneTags::ReadableStream,
TransferrableInterface::WritableStream => StructuredCloneTags::WritableStream,
+ TransferrableInterface::TransformStream => StructuredCloneTags::TransformStream,
}
}
}
@@ -265,6 +267,7 @@ fn receiver_for_type(
TransferrableInterface::MessagePort => receive_object::<MessagePort>,
TransferrableInterface::ReadableStream => receive_object::<ReadableStream>,
TransferrableInterface::WritableStream => receive_object::<WritableStream>,
+ TransferrableInterface::TransformStream => receive_object::<TransformStream>,
}
}
@@ -390,6 +393,7 @@ fn transfer_for_type(val: TransferrableInterface) -> TransferOperation {
TransferrableInterface::MessagePort => try_transfer::<MessagePort>,
TransferrableInterface::ReadableStream => try_transfer::<ReadableStream>,
TransferrableInterface::WritableStream => try_transfer::<WritableStream>,
+ TransferrableInterface::TransformStream => try_transfer::<TransformStream>,
}
}
@@ -438,6 +442,7 @@ unsafe fn can_transfer_for_type(
TransferrableInterface::MessagePort => can_transfer::<MessagePort>(obj, cx),
TransferrableInterface::ReadableStream => can_transfer::<ReadableStream>(obj, cx),
TransferrableInterface::WritableStream => can_transfer::<WritableStream>(obj, cx),
+ TransferrableInterface::TransformStream => can_transfer::<TransformStream>(obj, cx),
}
}
diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs
index 5722dc4f6ac..2e7c4cf8def 100644
--- a/components/script/dom/create.rs
+++ b/components/script/dom/create.rs
@@ -85,6 +85,7 @@ use crate::dom::htmlulistelement::HTMLUListElement;
use crate::dom::htmlunknownelement::HTMLUnknownElement;
use crate::dom::htmlvideoelement::HTMLVideoElement;
use crate::dom::svgelement::SVGElement;
+use crate::dom::svgimageelement::SVGImageElement;
use crate::dom::svgsvgelement::SVGSVGElement;
use crate::realms::{InRealm, enter_realm};
use crate::script_runtime::CanGc;
@@ -114,6 +115,7 @@ fn create_svg_element(
}
match name.local {
+ local_name!("image") => make!(SVGImageElement),
local_name!("svg") => make!(SVGSVGElement),
_ => make!(SVGElement),
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 5c79dbc0a5b..cb120f0b174 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -63,8 +63,9 @@ use xml5ever::serialize::TraversalScope::{
ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
};
+use crate::conversions::Convert;
use crate::dom::activation::Activatable;
-use crate::dom::attr::{Attr, AttrHelpersForLayout};
+use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute};
use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
@@ -80,7 +81,9 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
use crate::dom::bindings::codegen::Bindings::WindowBinding::{
ScrollBehavior, ScrollToOptions, WindowMethods,
};
-use crate::dom::bindings::codegen::UnionTypes::{NodeOrString, TrustedScriptURLOrUSVString};
+use crate::dom::bindings::codegen::UnionTypes::{
+ NodeOrString, TrustedHTMLOrNullIsEmptyString, TrustedHTMLOrString, TrustedScriptURLOrUSVString,
+};
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
@@ -152,6 +155,7 @@ use crate::dom::raredata::ElementRareData;
use crate::dom::servoparser::ServoParser;
use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
use crate::dom::text::Text;
+use crate::dom::trustedhtml::TrustedHTML;
use crate::dom::validation::Validatable;
use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -355,7 +359,7 @@ impl Element {
if damage == NodeDamage::OtherNodeDamage {
doc.note_node_with_dirty_descendants(self.upcast());
- restyle.damage = RestyleDamage::rebuild_and_reflow();
+ restyle.damage = RestyleDamage::reconstruct();
}
}
@@ -1701,7 +1705,7 @@ impl Element {
assert!(attr.GetOwnerElement().as_deref() == Some(self));
self.will_mutate_attr(attr);
self.attrs.borrow_mut().push(Dom::from_ref(attr));
- if attr.namespace() == &ns!() {
+ if is_relevant_attribute(attr.namespace(), attr.local_name()) {
vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None), can_gc);
}
}
@@ -1843,7 +1847,7 @@ impl Element {
local_name: &LocalName,
value: DOMString,
) -> AttrValue {
- if *namespace == ns!() {
+ if is_relevant_attribute(namespace, local_name) {
vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
} else {
AttrValue::String(value.into())
@@ -1898,7 +1902,7 @@ impl Element {
self.attrs.borrow_mut().remove(idx);
attr.set_owner(None);
- if attr.namespace() == &ns!() {
+ if is_relevant_attribute(attr.namespace(), attr.local_name()) {
vtable_for(self.upcast()).attribute_mutated(
&attr,
AttributeMutation::Removed,
@@ -1992,6 +1996,15 @@ impl Element {
.unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
}
+ pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
+ assert_eq!(*local_name, local_name.to_ascii_lowercase());
+ let value = match self.get_attribute(&ns!(), local_name) {
+ Some(attr) => (&**attr.value()).into(),
+ None => "".into(),
+ };
+ TrustedHTMLOrString::String(value)
+ }
+
pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
match self.get_attribute(&ns!(), local_name) {
Some(x) => x.Value(),
@@ -2322,18 +2335,25 @@ impl Element {
Ok(fragment)
}
+ /// Step 4 of <https://html.spec.whatwg.org/multipage/#dom-element-insertadjacenthtml>
pub(crate) fn fragment_parsing_context(
owner_doc: &Document,
element: Option<&Self>,
can_gc: CanGc,
) -> DomRoot<Self> {
+ // If context is not an Element or all of the following are true:
match element {
Some(elem)
+ // context's node document is an HTML document;
+ // context's local name is "html"; and
+ // context's namespace is the HTML namespace,
if elem.local_name() != &local_name!("html") ||
!elem.html_element_in_html_document() =>
{
DomRoot::from_ref(elem)
},
+ // set context to the result of creating an element
+ // given this's node document, "body", and the HTML namespace.
_ => DomRoot::upcast(HTMLBodyElement::new(
local_name!("body"),
None,
@@ -2446,6 +2466,13 @@ impl Element {
Dom::from_ref(&*ElementInternals::new(elem, can_gc))
}))
}
+
+ pub(crate) fn outer_html(&self, can_gc: CanGc) -> Fallible<DOMString> {
+ match self.GetOuterHTML(can_gc)? {
+ TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
+ TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
+ }
+ }
}
impl ElementMethods<crate::DomTypeHolder> for Element {
@@ -2704,7 +2731,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
attr.set_owner(Some(self));
self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
old_attr.set_owner(None);
- if attr.namespace() == &ns!() {
+ if is_relevant_attribute(attr.namespace(), attr.local_name()) {
vtable.attribute_mutated(
attr,
AttributeMutation::Set(Some(&old_attr.value())),
@@ -3100,7 +3127,17 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-sethtmlunsafe>
- fn SetHTMLUnsafe(&self, html: DOMString, can_gc: CanGc) {
+ fn SetHTMLUnsafe(&self, html: TrustedHTMLOrString, can_gc: CanGc) -> ErrorResult {
+ // Step 1. Let compliantHTML be the result of invoking the
+ // Get Trusted Type compliant string algorithm with TrustedHTML,
+ // this's relevant global object, html, "Element setHTMLUnsafe", and "script".
+ let html = DOMString::from(TrustedHTML::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ html,
+ "Element",
+ "setHTMLUnsafe",
+ can_gc,
+ )?);
// Step 2. Let target be this's template contents if this is a template element; otherwise this.
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
DomRoot::upcast(template.Content(can_gc))
@@ -3110,6 +3147,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
// Step 3. Unsafely set HTML given target, this, and compliantHTML
Node::unsafely_set_html(&target, self, html, can_gc);
+ Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-gethtml>
@@ -3125,7 +3163,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-innerhtml>
- fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<DOMString> {
+ fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
let qname = QualName::new(
self.prefix().clone(),
self.namespace().clone(),
@@ -3142,16 +3180,28 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
.xml_serialize(XmlChildrenOnly(Some(qname)))
};
- Ok(result)
+ Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-innerhtml>
- fn SetInnerHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult {
- // Step 2.
+ fn SetInnerHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
+ // Step 1: Let compliantString be the result of invoking the
+ // Get Trusted Type compliant string algorithm with TrustedHTML,
+ // this's relevant global object, the given value, "Element innerHTML", and "script".
+ let value = DOMString::from(TrustedHTML::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ value.convert(),
+ "Element",
+ "innerHTML",
+ can_gc,
+ )?);
// https://github.com/w3c/DOM-Parsing/issues/1
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
+ // Step 4: If context is a template element, then set context to
+ // the template element's template contents (a DocumentFragment).
DomRoot::upcast(template.Content(can_gc))
} else {
+ // Step 2: Let context be this.
DomRoot::from_ref(self.upcast())
};
@@ -3168,15 +3218,17 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
return Ok(());
}
- // Step 1.
+ // Step 3: Let fragment be the result of invoking the fragment parsing algorithm steps
+ // with context and compliantString.
let frag = self.parse_fragment(value, can_gc)?;
+ // Step 5: Replace all with fragment within context.
Node::replace_all(Some(frag.upcast()), &target, can_gc);
Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-outerhtml>
- fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<DOMString> {
+ fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
// FIXME: This should use the fragment serialization algorithm, which takes
// care of distinguishing between html/xml documents
let result = if self.owner_document().is_html_document() {
@@ -3186,27 +3238,39 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
self.upcast::<Node>().xml_serialize(XmlIncludeNode)
};
- Ok(result)
+ Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-outerhtml>
- fn SetOuterHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult {
+ fn SetOuterHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
+ // Step 1: Let compliantString be the result of invoking the
+ // Get Trusted Type compliant string algorithm with TrustedHTML,
+ // this's relevant global object, the given value, "Element outerHTML", and "script".
+ let value = DOMString::from(TrustedHTML::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ value.convert(),
+ "Element",
+ "outerHTML",
+ can_gc,
+ )?);
let context_document = self.owner_document();
let context_node = self.upcast::<Node>();
- // Step 1.
+ // Step 2: Let parent be this's parent.
let context_parent = match context_node.GetParentNode() {
None => {
- // Step 2.
+ // Step 3: If parent is null, return. There would be no way to
+ // obtain a reference to the nodes created even if the remaining steps were run.
return Ok(());
},
Some(parent) => parent,
};
let parent = match context_parent.type_id() {
- // Step 3.
+ // Step 4: If parent is a Document, throw a "NoModificationAllowedError" DOMException.
NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed),
- // Step 4.
+ // Step 5: If parent is a DocumentFragment, set parent to the result of
+ // creating an element given this's node document, "body", and the HTML namespace.
NodeTypeId::DocumentFragment(_) => {
let body_elem = Element::create(
QualName::new(None, ns!(html), local_name!("body")),
@@ -3222,9 +3286,10 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
_ => context_node.GetParentElement().unwrap(),
};
- // Step 5.
+ // Step 6: Let fragment be the result of invoking the
+ // fragment parsing algorithm steps given parent and compliantString.
let frag = parent.parse_fragment(value, can_gc)?;
- // Step 6.
+ // Step 7: Replace this with fragment within this's parent.
context_parent.ReplaceChild(frag.upcast(), context_node, can_gc)?;
Ok(())
}
@@ -3391,38 +3456,57 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
fn InsertAdjacentHTML(
&self,
position: DOMString,
- text: DOMString,
+ text: TrustedHTMLOrString,
can_gc: CanGc,
) -> ErrorResult {
- // Step 1.
+ // Step 1: Let compliantString be the result of invoking the
+ // Get Trusted Type compliant string algorithm with TrustedHTML,
+ // this's relevant global object, string, "Element insertAdjacentHTML", and "script".
+ let text = DOMString::from(TrustedHTML::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ text,
+ "Element",
+ "insertAdjacentHTML",
+ can_gc,
+ )?);
let position = position.parse::<AdjacentPosition>()?;
+ // Step 2: Let context be null.
+ // Step 3: Use the first matching item from this list:
let context = match position {
+ // If position is an ASCII case-insensitive match for the string "beforebegin"
+ // If position is an ASCII case-insensitive match for the string "afterend"
AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
match self.upcast::<Node>().GetParentNode() {
+ // Step 3.2: If context is null or a Document, throw a "NoModificationAllowedError" DOMException.
Some(ref node) if node.is::<Document>() => {
return Err(Error::NoModificationAllowed);
},
None => return Err(Error::NoModificationAllowed),
+ // Step 3.1: Set context to this's parent.
Some(node) => node,
}
},
+ // If position is an ASCII case-insensitive match for the string "afterbegin"
+ // If position is an ASCII case-insensitive match for the string "beforeend"
AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
+ // Set context to this.
DomRoot::from_ref(self.upcast::<Node>())
},
};
- // Step 2.
+ // Step 4.
let context = Element::fragment_parsing_context(
&context.owner_doc(),
context.downcast::<Element>(),
can_gc,
);
- // Step 3.
+ // Step 5: Let fragment be the result of invoking the
+ // fragment parsing algorithm steps with context and compliantString.
let fragment = context.parse_fragment(text, can_gc)?;
- // Step 4.
+ // Step 6.
self.insert_adjacent(position, fragment.upcast(), can_gc)
.map(|_| ())
}
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 902d4622db9..55db2e4d248 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -3562,10 +3562,6 @@ impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
GlobalScope::from_reflector(reflector, realm)
}
- unsafe fn from_object_maybe_wrapped(obj: *mut JSObject, cx: *mut JSContext) -> DomRoot<Self> {
- GlobalScope::from_object_maybe_wrapped(obj, cx)
- }
-
fn origin(&self) -> &MutableOrigin {
GlobalScope::origin(self)
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 0fbff86e44a..18116eee8ae 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -27,6 +27,8 @@ use crate::dom::attr::Attr;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
+use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::DomGlobal;
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
@@ -40,6 +42,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{Node, NodeDamage, NodeTraits, UnbindContext};
+use crate::dom::trustedhtml::TrustedHTML;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::CanGc;
@@ -595,10 +598,29 @@ impl HTMLIFrameElementMethods<crate::DomTypeHolder> for HTMLIFrameElement {
make_url_setter!(SetSrc, "src");
// https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
- make_getter!(Srcdoc, "srcdoc");
+ fn Srcdoc(&self) -> TrustedHTMLOrString {
+ let element = self.upcast::<Element>();
+ element.get_trusted_html_attribute(&local_name!("srcdoc"))
+ }
// https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
- make_setter!(SetSrcdoc, "srcdoc");
+ fn SetSrcdoc(&self, value: TrustedHTMLOrString, can_gc: CanGc) -> Fallible<()> {
+ // Step 1: Let compliantString be the result of invoking the
+ // Get Trusted Type compliant string algorithm with TrustedHTML,
+ // this's relevant global object, the given value, "HTMLIFrameElement srcdoc", and "script".
+ let element = self.upcast::<Element>();
+ let local_name = &local_name!("srcdoc");
+ let value = TrustedHTML::get_trusted_script_compliant_string(
+ &element.owner_global(),
+ value,
+ "HTMLIFrameElement",
+ local_name,
+ can_gc,
+ )?;
+ // Step 2: Set an attribute value given this, srcdoc's local name, and compliantString.
+ element.set_attribute(local_name, AttrValue::String(value), can_gc);
+ Ok(())
+ }
// https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
fn Sandbox(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 1622cf57b79..91a4e1b1359 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -547,6 +547,7 @@ pub(crate) mod submitevent;
pub(crate) mod subtlecrypto;
pub(crate) mod svgelement;
pub(crate) mod svggraphicselement;
+pub(crate) mod svgimageelement;
pub(crate) mod svgsvgelement;
pub(crate) mod testbinding;
pub(crate) mod testbindingiterable;
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index ca785773b48..5f08abce354 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -4207,6 +4207,9 @@ impl From<ElementTypeIdWrapper> for LayoutElementType {
LayoutElementType::HTMLTextAreaElement
},
ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
+ SVGGraphicsElementTypeId::SVGImageElement,
+ )) => LayoutElementType::SVGImageElement,
+ ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
SVGGraphicsElementTypeId::SVGSVGElement,
)) => LayoutElementType::SVGSVGElement,
_ => LayoutElementType::Element,
diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs
index 80b62f161bc..0efffbe6fe2 100644
--- a/components/script/dom/promise.rs
+++ b/components/script/dom/promise.rs
@@ -29,7 +29,6 @@ use js::rust::wrappers::{
ResolvePromise, SetAnyPromiseIsHandled, SetPromiseUserInputEventHandlingState,
};
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
-use script_bindings::interfaces::PromiseHelpers;
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::error::{Error, ErrorToJsval};
@@ -388,16 +387,6 @@ fn create_native_handler_function(
}
}
-impl PromiseHelpers<crate::DomTypeHolder> for Promise {
- fn new_resolved(
- global: &GlobalScope,
- cx: SafeJSContext,
- value: impl ToJSValConvertible,
- ) -> Rc<Promise> {
- Promise::new_resolved(global, cx, value, CanGc::note())
- }
-}
-
impl FromJSValConvertibleRc for Promise {
#[allow(unsafe_code)]
unsafe fn from_jsval(
@@ -407,16 +396,12 @@ impl FromJSValConvertibleRc for Promise {
if value.get().is_null() {
return Ok(ConversionResult::Failure("null not allowed".into()));
}
- if !value.get().is_object() {
- return Ok(ConversionResult::Failure("not an object".into()));
- }
- rooted!(in(cx) let obj = value.get().to_object());
let cx = SafeJSContext::from_ptr(cx);
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
let global_scope = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
- let promise = Promise::new_resolved(&global_scope, cx, *obj, CanGc::note());
+ let promise = Promise::new_resolved(&global_scope, cx, value, CanGc::note());
Ok(ConversionResult::Success(promise))
}
}
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index 4982bfa32e3..d631a01e1e7 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -11,6 +11,7 @@ use std::rc::Rc;
use base::id::{MessagePortId, MessagePortIndex};
use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
+use ipc_channel::ipc::IpcSharedMemory;
use js::conversions::ToJSValConvertible;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue};
@@ -1131,12 +1132,14 @@ impl ReadableStream {
/// Return bytes for synchronous use, if the stream has all data in memory.
/// Useful for native source integration only.
- pub(crate) fn get_in_memory_bytes(&self) -> Option<Vec<u8>> {
+ pub(crate) fn get_in_memory_bytes(&self) -> Option<IpcSharedMemory> {
match self.controller.borrow().as_ref() {
Some(ControllerType::Default(controller)) => controller
.get()
.expect("Stream should have controller.")
- .get_in_memory_bytes(),
+ .get_in_memory_bytes()
+ .as_deref()
+ .map(IpcSharedMemory::from_bytes),
_ => {
unreachable!("Getting in-memory bytes for a stream with a non-default controller")
},
diff --git a/components/script/dom/svgelement.rs b/components/script/dom/svgelement.rs
index 9c8b990826d..0f36d942f3e 100644
--- a/components/script/dom/svgelement.rs
+++ b/components/script/dom/svgelement.rs
@@ -82,6 +82,9 @@ impl SVGElementMethods<crate::DomTypeHolder> for SVGElement {
})
}
+ // <https://html.spec.whatwg.org/multipage/#globaleventhandlers>
+ global_event_handlers!();
+
// FIXME: The nonce should be stored in an internal slot instead of an
// attribute (https://html.spec.whatwg.org/multipage/#cryptographicnonce)
// https://html.spec.whatwg.org/multipage/#dom-noncedelement-nonce
diff --git a/components/script/dom/svgimageelement.rs b/components/script/dom/svgimageelement.rs
new file mode 100644
index 00000000000..17a5a9149d8
--- /dev/null
+++ b/components/script/dom/svgimageelement.rs
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use dom_struct::dom_struct;
+use html5ever::{LocalName, Prefix, local_name, ns};
+use js::rust::HandleObject;
+use style::attr::AttrValue;
+
+use crate::dom::attr::Attr;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::document::Document;
+use crate::dom::element::AttributeMutation;
+use crate::dom::node::{Node, NodeTraits};
+use crate::dom::svggraphicselement::SVGGraphicsElement;
+use crate::dom::virtualmethods::VirtualMethods;
+use crate::script_runtime::CanGc;
+
+/// <https://svgwg.org/svg2-draft/embedded.html#Placement>
+const DEFAULT_WIDTH: u32 = 300;
+const DEFAULT_HEIGHT: u32 = 150;
+
+#[dom_struct]
+pub(crate) struct SVGImageElement {
+ svggraphicselement: SVGGraphicsElement,
+}
+
+impl SVGImageElement {
+ fn new_inherited(
+ local_name: LocalName,
+ prefix: Option<Prefix>,
+ document: &Document,
+ ) -> SVGImageElement {
+ SVGImageElement {
+ svggraphicselement: SVGGraphicsElement::new_inherited(local_name, prefix, document),
+ }
+ }
+
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ pub(crate) fn new(
+ local_name: LocalName,
+ prefix: Option<Prefix>,
+ document: &Document,
+ proto: Option<HandleObject>,
+ can_gc: CanGc,
+ ) -> DomRoot<SVGImageElement> {
+ Node::reflect_node_with_proto(
+ Box::new(SVGImageElement::new_inherited(local_name, prefix, document)),
+ document,
+ proto,
+ can_gc,
+ )
+ }
+
+ /// <https://svgwg.org/svg2-draft/linking.html#processingURL>
+ fn fetch_image_resource(&self) {
+ // TODO: Process and fetch the image resource (as HTMLImageElement).
+ // Reject any resource fetching request immediately.
+ self.owner_global()
+ .task_manager()
+ .dom_manipulation_task_source()
+ .queue_simple_event(self.upcast(), atom!("error"));
+ }
+}
+
+impl VirtualMethods for SVGImageElement {
+ fn super_type(&self) -> Option<&dyn VirtualMethods> {
+ Some(self.upcast::<SVGGraphicsElement>() as &dyn VirtualMethods)
+ }
+
+ fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
+ self.super_type()
+ .unwrap()
+ .attribute_mutated(attr, mutation, can_gc);
+ if attr.local_name() == &local_name!("href") &&
+ matches!(attr.namespace(), &ns!() | &ns!(xlink))
+ {
+ if let AttributeMutation::Set(_) = mutation {
+ self.fetch_image_resource();
+ }
+ }
+ }
+
+ fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
+ match *name {
+ local_name!("width") => AttrValue::from_u32(value.into(), DEFAULT_WIDTH),
+ local_name!("height") => AttrValue::from_u32(value.into(), DEFAULT_HEIGHT),
+ _ => self
+ .super_type()
+ .unwrap()
+ .parse_plain_attribute(name, value),
+ }
+ }
+}
diff --git a/components/script/dom/transformstream.rs b/components/script/dom/transformstream.rs
index 023fe7ac483..0251498980d 100644
--- a/components/script/dom/transformstream.rs
+++ b/components/script/dom/transformstream.rs
@@ -3,9 +3,12 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::Cell;
+use std::collections::HashMap;
use std::ptr::{self};
use std::rc::Rc;
+use base::id::{MessagePortId, MessagePortIndex};
+use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
use js::jsapi::{Heap, IsPromiseObject, JSObject};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
@@ -14,6 +17,9 @@ use script_bindings::callback::ExceptionHandling;
use script_bindings::realms::InRealm;
use super::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategySize;
+use super::bindings::structuredclone::StructuredData;
+use super::bindings::transferable::Transferable;
+use super::messageport::MessagePort;
use super::promisenativehandler::Callback;
use super::types::{TransformStreamDefaultController, WritableStream};
use crate::dom::bindings::cell::DomRefCell;
@@ -997,3 +1003,103 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
self.writable.get().expect("writable stream is not set")
}
}
+
+/// <https://streams.spec.whatwg.org/#ts-transfer>
+impl Transferable for TransformStream {
+ type Index = MessagePortIndex;
+ type Data = MessagePortImpl;
+
+ fn transfer(&self) -> Result<(MessagePortId, MessagePortImpl), ()> {
+ let global = self.global();
+ let realm = enter_realm(&*global);
+ let comp = InRealm::Entered(&realm);
+ let cx = GlobalScope::get_cx();
+ let can_gc = CanGc::note();
+
+ // Let readable be value.[[readable]].
+ let readable = self.get_readable();
+
+ // Let writable be value.[[writable]].
+ let writable = self.get_writable();
+
+ // If ! IsReadableStreamLocked(readable) is true, throw a "DataCloneError" DOMException.
+ if readable.is_locked() {
+ return Err(());
+ }
+
+ // If ! IsWritableStreamLocked(writable) is true, throw a "DataCloneError" DOMException.
+ if writable.is_locked() {
+ return Err(());
+ }
+
+ // Create the shared port pair
+ let port_1 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port_1, None);
+ let port_2 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port_2, None);
+ global.entangle_ports(*port_1.message_port_id(), *port_2.message_port_id());
+
+ // Create a proxy WritableStream wired to port_1
+ let proxy_writable = WritableStream::new_with_proto(&global, None, can_gc);
+ proxy_writable.setup_cross_realm_transform_writable(cx, &port_1, can_gc);
+
+ // Pipe readable into the proxy writable (→ port_1)
+ let pipe1 = readable.pipe_to(
+ cx,
+ &global,
+ &proxy_writable,
+ false,
+ false,
+ false,
+ comp,
+ can_gc,
+ );
+ pipe1.set_promise_is_handled();
+
+ // Create a proxy ReadableStream wired to port_1
+ let proxy_readable = ReadableStream::new_with_proto(&global, None, can_gc);
+ proxy_readable.setup_cross_realm_transform_readable(cx, &port_1, can_gc);
+
+ // Pipe proxy readable (← port_1) into writable
+ let pipe2 =
+ proxy_readable.pipe_to(cx, &global, &writable, false, false, false, comp, can_gc);
+ pipe2.set_promise_is_handled();
+
+ // Set dataHolder.[[readable]] to ! StructuredSerializeWithTransfer(readable, « readable »).
+ // Set dataHolder.[[writable]] to ! StructuredSerializeWithTransfer(writable, « writable »).
+ port_2.transfer()
+ }
+
+ fn transfer_receive(
+ owner: &GlobalScope,
+ id: MessagePortId,
+ port_impl: MessagePortImpl,
+ ) -> Result<DomRoot<Self>, ()> {
+ let can_gc = CanGc::note();
+
+ // Let readableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[readable]], the current Realm).
+ // Set value.[[readable]] to readableRecord.[[Deserialized]].
+ let readable = ReadableStream::transfer_receive(owner, id, port_impl.clone())?;
+
+ // Let writableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[writable]], the current Realm).
+ let writable = WritableStream::transfer_receive(owner, id, port_impl)?;
+
+ // Set value.[[readable]] to readableRecord.[[Deserialized]].
+ // Set value.[[writable]] to writableRecord.[[Deserialized]].
+ // Set value.[[backpressure]], value.[[backpressureChangePromise]], and value.[[controller]] to undefined.
+ let stream = TransformStream::new_with_proto(owner, None, can_gc);
+ stream.readable.set(Some(&readable));
+ stream.writable.set(Some(&writable));
+
+ Ok(stream)
+ }
+
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> {
+ match data {
+ StructuredData::Reader(r) => &mut r.port_impls,
+ StructuredData::Writer(w) => &mut w.ports,
+ }
+ }
+}
diff --git a/components/script/dom/trustedhtml.rs b/components/script/dom/trustedhtml.rs
index 8508f28c150..d1ca3cd5e71 100644
--- a/components/script/dom/trustedhtml.rs
+++ b/components/script/dom/trustedhtml.rs
@@ -6,8 +6,11 @@ use std::fmt;
use dom_struct::dom_struct;
+use crate::conversions::Convert;
use crate::dom::bindings::codegen::Bindings::TrustedHTMLBinding::TrustedHTMLMethods;
-use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
+use crate::dom::bindings::codegen::UnionTypes::{
+ TrustedHTMLOrNullIsEmptyString, TrustedHTMLOrString,
+};
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
@@ -80,3 +83,16 @@ impl TrustedHTMLMethods<crate::DomTypeHolder> for TrustedHTML {
DOMString::from(&*self.data)
}
}
+
+impl Convert<TrustedHTMLOrString> for TrustedHTMLOrNullIsEmptyString {
+ fn convert(self) -> TrustedHTMLOrString {
+ match self {
+ TrustedHTMLOrNullIsEmptyString::TrustedHTML(trusted_html) => {
+ TrustedHTMLOrString::TrustedHTML(trusted_html)
+ },
+ TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => {
+ TrustedHTMLOrString::String(str)
+ },
+ }
+ }
+}
diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs
index 57ecba7b172..1d992b1f301 100644
--- a/components/script/dom/virtualmethods.rs
+++ b/components/script/dom/virtualmethods.rs
@@ -61,6 +61,7 @@ use crate::dom::htmlvideoelement::HTMLVideoElement;
use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext};
use crate::dom::shadowroot::ShadowRoot;
use crate::dom::svgelement::SVGElement;
+use crate::dom::svgimageelement::SVGImageElement;
use crate::dom::svgsvgelement::SVGSVGElement;
/// Trait to allow DOM nodes to opt-in to overriding (or adding to) common
@@ -299,6 +300,9 @@ pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
},
NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
+ SVGGraphicsElementTypeId::SVGImageElement,
+ ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
+ NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
SVGGraphicsElementTypeId::SVGSVGElement,
))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => {
diff --git a/components/script/messaging.rs b/components/script/messaging.rs
index e0ea9e30af2..08d6fc841cf 100644
--- a/components/script/messaging.rs
+++ b/components/script/messaging.rs
@@ -91,6 +91,7 @@ impl MixedMessage {
#[cfg(feature = "webgpu")]
ScriptThreadMessage::SetWebGPUPort(..) => None,
ScriptThreadMessage::SetScrollStates(id, ..) => Some(*id),
+ ScriptThreadMessage::EvaluateJavaScript(id, _, _) => Some(*id),
},
MixedMessage::FromScript(inner_msg) => match inner_msg {
MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index d6ab18be49b..4815e6feae1 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -50,9 +50,9 @@ use devtools_traits::{
};
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{
- CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent, MediaSessionActionType,
- MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails,
- WebDriverScriptCommand,
+ CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent,
+ JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, MouseButton,
+ MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand,
};
use euclid::Point2D;
use euclid::default::Rect;
@@ -156,6 +156,7 @@ use crate::script_runtime::{
};
use crate::task_queue::TaskQueue;
use crate::task_source::{SendableTaskSource, TaskSourceName};
+use crate::webdriver_handlers::jsval_to_webdriver;
use crate::{devtools, webdriver_handlers};
thread_local!(static SCRIPT_THREAD_ROOT: Cell<Option<*const ScriptThread>> = const { Cell::new(None) });
@@ -1878,6 +1879,9 @@ impl ScriptThread {
ScriptThreadMessage::SetScrollStates(pipeline_id, scroll_states) => {
self.handle_set_scroll_states(pipeline_id, scroll_states)
},
+ ScriptThreadMessage::EvaluateJavaScript(pipeline_id, evaluation_id, script) => {
+ self.handle_evaluate_javascript(pipeline_id, evaluation_id, script, can_gc);
+ },
}
}
@@ -3815,6 +3819,53 @@ impl ScriptThread {
)
}
}
+
+ fn handle_evaluate_javascript(
+ &self,
+ pipeline_id: PipelineId,
+ evaluation_id: JavaScriptEvaluationId,
+ script: String,
+ can_gc: CanGc,
+ ) {
+ let Some(window) = self.documents.borrow().find_window(pipeline_id) else {
+ let _ = self.senders.pipeline_to_constellation_sender.send((
+ pipeline_id,
+ ScriptToConstellationMessage::FinishJavaScriptEvaluation(
+ evaluation_id,
+ Err(JavaScriptEvaluationError::WebViewNotReady),
+ ),
+ ));
+ return;
+ };
+
+ let global_scope = window.as_global_scope();
+ let realm = enter_realm(global_scope);
+ let context = window.get_cx();
+
+ rooted!(in(*context) let mut return_value = UndefinedValue());
+ global_scope.evaluate_js_on_global_with_result(
+ &script,
+ return_value.handle_mut(),
+ ScriptFetchOptions::default_classic_script(global_scope),
+ global_scope.api_base_url(),
+ can_gc,
+ );
+ let result = match jsval_to_webdriver(
+ context,
+ global_scope,
+ return_value.handle(),
+ (&realm).into(),
+ can_gc,
+ ) {
+ Ok(ref value) => Ok(value.into()),
+ Err(_) => Err(JavaScriptEvaluationError::SerializationError),
+ };
+
+ let _ = self.senders.pipeline_to_constellation_sender.send((
+ pipeline_id,
+ ScriptToConstellationMessage::FinishJavaScriptEvaluation(evaluation_id, result),
+ ));
+ }
}
impl Drop for ScriptThread {
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 330ae4f0788..6b4264d945e 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -902,7 +902,7 @@ pub(crate) fn handle_get_page_source(
.find_document(pipeline)
.ok_or(ErrorStatus::UnknownError)
.and_then(|document| match document.GetDocumentElement() {
- Some(element) => match element.GetOuterHTML(can_gc) {
+ Some(element) => match element.outer_html(can_gc) {
Ok(source) => Ok(source.to_string()),
Err(_) => {
match XMLSerializer::new(document.window(), None, can_gc)
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index 2a9874a386f..92871bc54aa 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -371,7 +371,7 @@ DOMInterfaces = {
},
'HTMLIFrameElement': {
- 'canGc': ['Sandbox'],
+ 'canGc': ['Sandbox', 'SetSrcdoc'],
},
'HTMLImageElement': {
@@ -538,7 +538,7 @@ DOMInterfaces = {
'Promise': {
'spiderMonkeyInterface': True,
- 'additionalTraits': ["crate::interfaces::PromiseHelpers<Self>", "js::conversions::FromJSValConvertibleRc"]
+ 'additionalTraits': ["js::conversions::FromJSValConvertibleRc"]
},
'Range': {
diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py
index 48f024be70f..458aa7508b0 100644
--- a/components/script_bindings/codegen/CodegenRust.py
+++ b/components/script_bindings/codegen/CodegenRust.py
@@ -742,6 +742,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"}")
return templateBody
+ # A helper function for types that implement FromJSValConvertible trait
+ def fromJSValTemplate(config, errorHandler, exceptionCode):
+ return f"""match FromJSValConvertible::from_jsval(*cx, ${{val}}, {config}) {{
+ Ok(ConversionResult::Success(value)) => value,
+ Ok(ConversionResult::Failure(error)) => {{
+ {errorHandler}
+ }}
+ _ => {{
+ {exceptionCode}
+ }},
+}}
+"""
+
assert not (isEnforceRange and isClamp) # These are mutually exclusive
if type.isSequence() or type.isRecord():
@@ -755,13 +768,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=" >")
- templateBody = (f"match FromJSValConvertible::from_jsval(*cx, ${{val}}, {config}) {{\n"
- " Ok(ConversionResult::Success(value)) => value,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ templateBody = fromJSValTemplate(config, failOrPropagate, exceptionCode)
return handleOptional(templateBody, declType, handleDefault("None"))
@@ -770,13 +777,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=" >")
- templateBody = ("match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
- " Ok(ConversionResult::Success(value)) => value,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ templateBody = fromJSValTemplate("()", failOrPropagate, exceptionCode)
dictionaries = [
memberType
@@ -836,21 +837,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# once again be providing a Promise to signal completion of an
# operation, which would then not be exposed to anyone other than
# our own implementation code.
- templateBody = fill(
- """
- { // Scope for our JSAutoRealm.
-
- rooted!(in(*cx) let globalObj = CurrentGlobalOrNull(*cx));
- let promiseGlobal = D::GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), *cx);
-
- rooted!(in(*cx) let mut valueToResolve = $${val}.get());
- if !JS_WrapValue(*cx, valueToResolve.handle_mut()) {
- $*{exceptionCode}
- }
- D::Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle())
- }
- """,
- exceptionCode=exceptionCode)
+ templateBody = fromJSValTemplate("()", failOrPropagate, exceptionCode)
if isArgument:
declType = CGGeneric("&D::Promise")
@@ -960,14 +947,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isDOMString():
nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
- conversionCode = (
- f"match FromJSValConvertible::from_jsval(*cx, ${{val}}, {nullBehavior}) {{\n"
- " Ok(ConversionResult::Success(strval)) => strval,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ conversionCode = fromJSValTemplate(nullBehavior, failOrPropagate, exceptionCode)
if defaultValue is None:
default = None
@@ -989,14 +969,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isUSVString():
assert not isEnforceRange and not isClamp
- conversionCode = (
- "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
- " Ok(ConversionResult::Success(strval)) => strval,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ conversionCode = fromJSValTemplate("()", failOrPropagate, exceptionCode)
if defaultValue is None:
default = None
@@ -1018,14 +991,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isByteString():
assert not isEnforceRange and not isClamp
- conversionCode = (
- "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
- " Ok(ConversionResult::Success(strval)) => strval,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ conversionCode = fromJSValTemplate("()", failOrPropagate, exceptionCode)
if defaultValue is None:
default = None
@@ -1056,12 +1022,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
handleInvalidEnumValueCode = "return true;"
- template = (
- "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {"
- f" Err(_) => {{ {exceptionCode} }},\n"
- " Ok(ConversionResult::Success(v)) => v,\n"
- f" Ok(ConversionResult::Failure(error)) => {{ {handleInvalidEnumValueCode} }},\n"
- "}")
+ template = fromJSValTemplate("()", handleInvalidEnumValueCode, exceptionCode)
if defaultValue is not None:
assert defaultValue.type.tag() == IDLType.Tags.domstring
@@ -1192,14 +1153,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type_needs_tracing(type):
declType = CGTemplatedType("RootedTraceableBox", declType)
- template = (
- "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n"
- " Ok(ConversionResult::Success(dictionary)) => dictionary,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }},\n"
- "}")
+ template = fromJSValTemplate("()", failOrPropagate, exceptionCode)
return handleOptional(template, declType, handleDefault(empty))
@@ -1220,14 +1174,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=">")
- template = (
- f"match FromJSValConvertible::from_jsval(*cx, ${{val}}, {conversionBehavior}) {{\n"
- " Ok(ConversionResult::Success(v)) => v,\n"
- " Ok(ConversionResult::Failure(error)) => {\n"
- f"{indent(failOrPropagate, 8)}\n"
- " }\n"
- f" _ => {{ {exceptionCode} }}\n"
- "}")
+ template = fromJSValTemplate(conversionBehavior, failOrPropagate, exceptionCode)
if defaultValue is not None:
if isinstance(defaultValue, IDLNullValue):
diff --git a/components/script_bindings/import.rs b/components/script_bindings/import.rs
index 16cc92f07bf..25bd6c38669 100644
--- a/components/script_bindings/import.rs
+++ b/components/script_bindings/import.rs
@@ -11,12 +11,12 @@ pub(crate) mod base {
};
pub(crate) use js::error::throw_type_error;
pub(crate) use js::jsapi::{
- CurrentGlobalOrNull, HandleValue as RawHandleValue, HandleValueArray, Heap, IsCallable,
- JS_NewObject, JSContext, JSObject,
+ HandleValue as RawHandleValue, HandleValueArray, Heap, IsCallable, JS_NewObject, JSContext,
+ JSObject,
};
pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue};
pub(crate) use js::panic::maybe_resume_unwind;
- pub(crate) use js::rust::wrappers::{Call, JS_WrapValue};
+ pub(crate) use js::rust::wrappers::Call;
pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue};
pub(crate) use crate::callback::{
diff --git a/components/script_bindings/interfaces.rs b/components/script_bindings/interfaces.rs
index b289737143e..58917283170 100644
--- a/components/script_bindings/interfaces.rs
+++ b/components/script_bindings/interfaces.rs
@@ -3,10 +3,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::RefCell;
-use std::rc::Rc;
use std::thread::LocalKey;
-use js::conversions::ToJSValConvertible;
use js::glue::JSPrincipalsCallbacks;
use js::jsapi::{CallArgs, HandleObject as RawHandleObject, JSContext as RawJSContext, JSObject};
use js::rust::{HandleObject, MutableHandleObject};
@@ -78,14 +76,6 @@ pub trait GlobalScopeHelpers<D: DomTypes> {
unsafe fn from_object(obj: *mut JSObject) -> DomRoot<D::GlobalScope>;
fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<D::GlobalScope>;
- /// # Safety
- /// `obj` must point to a valid, non-null JSObject.
- /// `cx` must point to a valid, non-null RawJSContext.
- unsafe fn from_object_maybe_wrapped(
- obj: *mut JSObject,
- cx: *mut RawJSContext,
- ) -> DomRoot<D::GlobalScope>;
-
fn origin(&self) -> &MutableOrigin;
fn incumbent() -> Option<DomRoot<D::GlobalScope>>;
@@ -101,15 +91,6 @@ pub trait DocumentHelpers {
fn ensure_safe_to_run_script_or_layout(&self);
}
-/// Operations that must be invoked from the generated bindings.
-pub trait PromiseHelpers<D: crate::DomTypes> {
- fn new_resolved(
- global: &D::GlobalScope,
- cx: JSContext,
- value: impl ToJSValConvertible,
- ) -> Rc<D::Promise>;
-}
-
pub trait ServoInternalsHelpers {
fn is_servo_internal(cx: JSContext, global: HandleObject) -> bool;
}
diff --git a/components/script_bindings/webidls/Element.webidl b/components/script_bindings/webidls/Element.webidl
index 0d2e204ae52..42733b91929 100644
--- a/components/script_bindings/webidls/Element.webidl
+++ b/components/script_bindings/webidls/Element.webidl
@@ -82,7 +82,7 @@ interface Element : Node {
[Throws]
undefined insertAdjacentText(DOMString where_, DOMString data);
[CEReactions, Throws]
- undefined insertAdjacentHTML(DOMString position, DOMString html);
+ undefined insertAdjacentHTML(DOMString position, (TrustedHTML or DOMString) string);
[Throws, Pref="dom_shadowdom_enabled"] ShadowRoot attachShadow(ShadowRootInit init);
readonly attribute ShadowRoot? shadowRoot;
@@ -122,11 +122,11 @@ partial interface Element {
// https://html.spec.whatwg.org/multipage/#dom-parsing-and-serialization
partial interface Element {
- [CEReactions] undefined setHTMLUnsafe(DOMString html);
+ [CEReactions, Throws] undefined setHTMLUnsafe((TrustedHTML or DOMString) html);
DOMString getHTML(optional GetHTMLOptions options = {});
- [CEReactions, Throws] attribute [LegacyNullToEmptyString] DOMString innerHTML;
- [CEReactions, Throws] attribute [LegacyNullToEmptyString] DOMString outerHTML;
+ [CEReactions, Throws] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) innerHTML;
+ [CEReactions, Throws] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) outerHTML;
};
dictionary GetHTMLOptions {
diff --git a/components/script_bindings/webidls/HTMLIFrameElement.webidl b/components/script_bindings/webidls/HTMLIFrameElement.webidl
index 8ba58a20f33..b083f51c0f1 100644
--- a/components/script_bindings/webidls/HTMLIFrameElement.webidl
+++ b/components/script_bindings/webidls/HTMLIFrameElement.webidl
@@ -9,8 +9,8 @@ interface HTMLIFrameElement : HTMLElement {
[CEReactions]
attribute USVString src;
- [CEReactions]
- attribute DOMString srcdoc;
+ [CEReactions, SetterThrows]
+ attribute (TrustedHTML or DOMString) srcdoc;
[CEReactions]
attribute DOMString name;
diff --git a/components/script_bindings/webidls/SVGElement.webidl b/components/script_bindings/webidls/SVGElement.webidl
index e6bc468d5dc..08bcb4a8c99 100644
--- a/components/script_bindings/webidls/SVGElement.webidl
+++ b/components/script_bindings/webidls/SVGElement.webidl
@@ -18,7 +18,7 @@ interface SVGElement : Element {
//void blur();
};
-//SVGElement includes GlobalEventHandlers;
+SVGElement includes GlobalEventHandlers;
//SVGElement includes SVGElementInstance;
SVGElement includes ElementCSSInlineStyle;
SVGElement includes HTMLOrSVGElement;
diff --git a/components/script_bindings/webidls/SVGImageElement.webidl b/components/script_bindings/webidls/SVGImageElement.webidl
new file mode 100644
index 00000000000..bced6277c5e
--- /dev/null
+++ b/components/script_bindings/webidls/SVGImageElement.webidl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://svgwg.org/svg2-draft/embedded.html#InterfaceSVGImageElement
+[Exposed=Window, Pref="dom_svg_enabled"]
+interface SVGImageElement : SVGGraphicsElement {
+ //[SameObject] readonly attribute SVGAnimatedLength x;
+ //[SameObject] readonly attribute SVGAnimatedLength y;
+ //[SameObject] readonly attribute SVGAnimatedLength width;
+ //[SameObject] readonly attribute SVGAnimatedLength height;
+ //[SameObject] readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
+ //attribute DOMString? crossOrigin;
+};
+
+//SVGImageElement includes SVGURIReference;
diff --git a/components/servo/javascript_evaluator.rs b/components/servo/javascript_evaluator.rs
new file mode 100644
index 00000000000..41cb5539b05
--- /dev/null
+++ b/components/servo/javascript_evaluator.rs
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use std::collections::HashMap;
+
+use base::id::WebViewId;
+use constellation_traits::EmbedderToConstellationMessage;
+use embedder_traits::{JSValue, JavaScriptEvaluationError, JavaScriptEvaluationId};
+
+use crate::ConstellationProxy;
+
+struct PendingEvaluation {
+ callback: Box<dyn FnOnce(Result<JSValue, JavaScriptEvaluationError>)>,
+}
+
+pub(crate) struct JavaScriptEvaluator {
+ current_id: JavaScriptEvaluationId,
+ constellation_proxy: ConstellationProxy,
+ pending_evaluations: HashMap<JavaScriptEvaluationId, PendingEvaluation>,
+}
+
+impl JavaScriptEvaluator {
+ pub(crate) fn new(constellation_proxy: ConstellationProxy) -> Self {
+ Self {
+ current_id: JavaScriptEvaluationId(0),
+ constellation_proxy,
+ pending_evaluations: Default::default(),
+ }
+ }
+
+ fn generate_id(&mut self) -> JavaScriptEvaluationId {
+ let next_id = JavaScriptEvaluationId(self.current_id.0 + 1);
+ std::mem::replace(&mut self.current_id, next_id)
+ }
+
+ pub(crate) fn evaluate(
+ &mut self,
+ webview_id: WebViewId,
+ script: String,
+ callback: Box<dyn FnOnce(Result<JSValue, JavaScriptEvaluationError>)>,
+ ) {
+ let evaluation_id = self.generate_id();
+ self.constellation_proxy
+ .send(EmbedderToConstellationMessage::EvaluateJavaScript(
+ webview_id,
+ evaluation_id,
+ script,
+ ));
+ self.pending_evaluations
+ .insert(evaluation_id, PendingEvaluation { callback });
+ }
+
+ pub(crate) fn finish_evaluation(
+ &mut self,
+ evaluation_id: JavaScriptEvaluationId,
+ result: Result<JSValue, JavaScriptEvaluationError>,
+ ) {
+ (self
+ .pending_evaluations
+ .remove(&evaluation_id)
+ .expect("Received request to finish unknown JavaScript evaluation.")
+ .callback)(result)
+ }
+}
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index b8210450cd8..d2c65429ba9 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -18,6 +18,7 @@
//! `WindowMethods` trait.
mod clipboard_delegate;
+mod javascript_evaluator;
mod proxies;
mod responders;
mod servo_delegate;
@@ -82,6 +83,7 @@ pub use gleam::gl;
use gleam::gl::RENDERER;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
+use javascript_evaluator::JavaScriptEvaluator;
pub use keyboard_types::*;
use layout::LayoutFactoryImpl;
use log::{Log, Metadata, Record, debug, warn};
@@ -196,6 +198,9 @@ pub struct Servo {
compositor: Rc<RefCell<IOCompositor>>,
constellation_proxy: ConstellationProxy,
embedder_receiver: Receiver<EmbedderMsg>,
+ /// A struct that tracks ongoing JavaScript evaluations and is responsible for
+ /// calling the callback when the evaluation is complete.
+ javascript_evaluator: Rc<RefCell<JavaScriptEvaluator>>,
/// Tracks whether we are in the process of shutting down, or have shut down.
/// This is shared with `WebView`s and the `ServoRenderer`.
shutdown_state: Rc<Cell<ShutdownState>>,
@@ -487,10 +492,14 @@ impl Servo {
opts.debug.convert_mouse_to_touch,
);
+ let constellation_proxy = ConstellationProxy::new(constellation_chan);
Self {
delegate: RefCell::new(Rc::new(DefaultServoDelegate)),
compositor: Rc::new(RefCell::new(compositor)),
- constellation_proxy: ConstellationProxy::new(constellation_chan),
+ javascript_evaluator: Rc::new(RefCell::new(JavaScriptEvaluator::new(
+ constellation_proxy.clone(),
+ ))),
+ constellation_proxy,
embedder_receiver,
shutdown_state,
webviews: Default::default(),
@@ -738,6 +747,11 @@ impl Servo {
webview.delegate().request_unload(webview, request);
}
},
+ EmbedderMsg::FinishJavaScriptEvaluation(evaluation_id, result) => {
+ self.javascript_evaluator
+ .borrow_mut()
+ .finish_evaluation(evaluation_id, result);
+ },
EmbedderMsg::Keyboard(webview_id, keyboard_event) => {
if let Some(webview) = self.get_webview_handle(webview_id) {
webview
diff --git a/components/servo/tests/webview.rs b/components/servo/tests/webview.rs
index 89fbe2025a3..41900015b94 100644
--- a/components/servo/tests/webview.rs
+++ b/components/servo/tests/webview.rs
@@ -11,12 +11,14 @@
mod common;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::rc::Rc;
use anyhow::ensure;
use common::{ServoTest, run_api_tests};
-use servo::{WebViewBuilder, WebViewDelegate};
+use servo::{
+ JSValue, JavaScriptEvaluationError, LoadStatus, WebView, WebViewBuilder, WebViewDelegate,
+};
#[derive(Default)]
struct WebViewDelegateImpl {
@@ -44,6 +46,81 @@ fn test_create_webview(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
Ok(())
}
+fn evaluate_javascript(
+ servo_test: &ServoTest,
+ webview: WebView,
+ script: impl ToString,
+) -> Result<JSValue, JavaScriptEvaluationError> {
+ let load_webview = webview.clone();
+ let _ = servo_test.spin(move || Ok(load_webview.load_status() != LoadStatus::Complete));
+
+ let saved_result = Rc::new(RefCell::new(None));
+ let callback_result = saved_result.clone();
+ webview.evaluate_javascript(script, move |result| {
+ *callback_result.borrow_mut() = Some(result)
+ });
+
+ let spin_result = saved_result.clone();
+ let _ = servo_test.spin(move || Ok(spin_result.borrow().is_none()));
+
+ (*saved_result.borrow())
+ .clone()
+ .expect("Should have waited until value available")
+}
+
+fn test_evaluate_javascript_basic(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
+ let delegate = Rc::new(WebViewDelegateImpl::default());
+ let webview = WebViewBuilder::new(servo_test.servo())
+ .delegate(delegate.clone())
+ .build();
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "undefined");
+ ensure!(result == Ok(JSValue::Undefined));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "null");
+ ensure!(result == Ok(JSValue::Null));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "42");
+ ensure!(result == Ok(JSValue::Number(42.0)));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "3 + 4");
+ ensure!(result == Ok(JSValue::Number(7.0)));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "'abc' + 'def'");
+ ensure!(result == Ok(JSValue::String("abcdef".into())));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "let foo = {blah: 123}; foo");
+ ensure!(matches!(result, Ok(JSValue::Object(_))));
+ if let Ok(JSValue::Object(values)) = result {
+ ensure!(values.len() == 1);
+ ensure!(values.get("blah") == Some(&JSValue::Number(123.0)));
+ }
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "[1, 2, 3, 4]");
+ let expected = JSValue::Array(vec![
+ JSValue::Number(1.0),
+ JSValue::Number(2.0),
+ JSValue::Number(3.0),
+ JSValue::Number(4.0),
+ ]);
+ ensure!(result == Ok(expected));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "window");
+ ensure!(matches!(result, Ok(JSValue::Window(..))));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "document.body");
+ ensure!(matches!(result, Ok(JSValue::Element(..))));
+
+ let result = evaluate_javascript(
+ servo_test,
+ webview.clone(),
+ "document.body.innerHTML += '<iframe>'; frames[0]",
+ );
+ ensure!(matches!(result, Ok(JSValue::Frame(..))));
+
+ Ok(())
+}
+
fn test_create_webview_and_immediately_drop_webview_before_shutdown(
servo_test: &ServoTest,
) -> Result<(), anyhow::Error> {
@@ -54,6 +131,7 @@ fn test_create_webview_and_immediately_drop_webview_before_shutdown(
fn main() {
run_api_tests!(
test_create_webview,
+ test_evaluate_javascript_basic,
// This test needs to be last, as it tests creating and dropping
// a WebView right before shutdown.
test_create_webview_and_immediately_drop_webview_before_shutdown
diff --git a/components/servo/webview.rs b/components/servo/webview.rs
index 95eb6dfd154..10786ad8b69 100644
--- a/components/servo/webview.rs
+++ b/components/servo/webview.rs
@@ -13,8 +13,8 @@ use compositing_traits::WebViewTrait;
use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use dpi::PhysicalSize;
use embedder_traits::{
- Cursor, InputEvent, LoadStatus, MediaSessionActionType, ScreenGeometry, Theme, TouchEventType,
- ViewportDetails,
+ Cursor, InputEvent, JSValue, JavaScriptEvaluationError, LoadStatus, MediaSessionActionType,
+ ScreenGeometry, Theme, TouchEventType, ViewportDetails,
};
use euclid::{Point2D, Scale, Size2D};
use servo_geometry::DeviceIndependentPixel;
@@ -23,6 +23,7 @@ use webrender_api::ScrollLocation;
use webrender_api::units::{DeviceIntPoint, DevicePixel, DeviceRect};
use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate};
+use crate::javascript_evaluator::JavaScriptEvaluator;
use crate::webview_delegate::{DefaultWebViewDelegate, WebViewDelegate};
use crate::{ConstellationProxy, Servo, WebRenderDebugOption};
@@ -75,6 +76,7 @@ pub(crate) struct WebViewInner {
pub(crate) compositor: Rc<RefCell<IOCompositor>>,
pub(crate) delegate: Rc<dyn WebViewDelegate>,
pub(crate) clipboard_delegate: Rc<dyn ClipboardDelegate>,
+ javascript_evaluator: Rc<RefCell<JavaScriptEvaluator>>,
rect: DeviceRect,
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
@@ -117,9 +119,10 @@ impl WebView {
compositor: servo.compositor.clone(),
delegate: builder.delegate,
clipboard_delegate: Rc::new(DefaultClipboardDelegate),
+ javascript_evaluator: servo.javascript_evaluator.clone(),
rect: DeviceRect::from_origin_and_size(Point2D::origin(), size),
hidpi_scale_factor: builder.hidpi_scale_factor,
- load_status: LoadStatus::Complete,
+ load_status: LoadStatus::Started,
url: None,
status_text: None,
page_title: None,
@@ -549,6 +552,20 @@ impl WebView {
pub fn paint(&self) -> bool {
self.inner().compositor.borrow_mut().render()
}
+
+ /// Evaluate the specified string of JavaScript code. Once execution is complete or an error
+ /// occurs, Servo will call `callback`.
+ pub fn evaluate_javascript<T: ToString>(
+ &self,
+ script: T,
+ callback: impl FnOnce(Result<JSValue, JavaScriptEvaluationError>) + 'static,
+ ) {
+ self.inner().javascript_evaluator.borrow_mut().evaluate(
+ self.id(),
+ script.to_string(),
+ Box::new(callback),
+ );
+ }
}
/// A structure used to expose a view of the [`WebView`] to the Servo
diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs
index 21665c24e57..3856def660e 100644
--- a/components/shared/constellation/from_script_message.rs
+++ b/components/shared/constellation/from_script_message.rs
@@ -15,8 +15,8 @@ use base::id::{
use canvas_traits::canvas::{CanvasId, CanvasMsg};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{
- AnimationState, EmbedderMsg, FocusSequenceNumber, MediaSessionEvent, TouchEventResult,
- ViewportDetails,
+ AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
+ JavaScriptEvaluationId, MediaSessionEvent, TouchEventResult, ViewportDetails,
};
use euclid::default::Size2D as UntypedSize2D;
use http::{HeaderMap, Method};
@@ -644,6 +644,11 @@ pub enum ScriptToConstellationMessage {
IFrameSizes(Vec<IFrameSizeMsg>),
/// Request results from the memory reporter.
ReportMemory(IpcSender<MemoryReportResult>),
+ /// Return the result of the evaluated JavaScript with the given [`JavaScriptEvaluationId`].
+ FinishJavaScriptEvaluation(
+ JavaScriptEvaluationId,
+ Result<JSValue, JavaScriptEvaluationError>,
+ ),
}
impl fmt::Debug for ScriptToConstellationMessage {
diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs
index 559bc2dd2d1..d85fbe31bdf 100644
--- a/components/shared/constellation/lib.rs
+++ b/components/shared/constellation/lib.rs
@@ -19,8 +19,8 @@ use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{MessagePortId, PipelineId, WebViewId};
use embedder_traits::{
- CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
- WebDriverCommandMsg,
+ CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
+ Theme, ViewportDetails, WebDriverCommandMsg,
};
use euclid::Vector2D;
pub use from_script_message::*;
@@ -92,6 +92,9 @@ pub enum EmbedderToConstellationMessage {
SetScrollStates(PipelineId, Vec<ScrollState>),
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
PaintMetric(PipelineId, PaintMetricEvent),
+ /// Evaluate a JavaScript string in the context of a `WebView`. When execution is complete or an
+ /// error is encountered, a correpsonding message will be sent to the embedding layer.
+ EvaluateJavaScript(WebViewId, JavaScriptEvaluationId, String),
}
/// A description of a paint metric that is sent from the Servo renderer to the
@@ -149,7 +152,7 @@ pub enum TraversalDirection {
}
/// A task on the <https://html.spec.whatwg.org/multipage/#port-message-queue>
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct PortMessageTask {
/// The origin of this task.
pub origin: ImmutableOrigin,
diff --git a/components/shared/constellation/structured_data/mod.rs b/components/shared/constellation/structured_data/mod.rs
index 41fc05493a2..3fb9d0c5f67 100644
--- a/components/shared/constellation/structured_data/mod.rs
+++ b/components/shared/constellation/structured_data/mod.rs
@@ -20,7 +20,7 @@ pub use transferable::*;
/// A data-holder for serialized data and transferred objects.
/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
-#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
pub struct StructuredSerializedData {
/// Data serialized by SpiderMonkey.
pub serialized: Vec<u8>,
@@ -43,6 +43,7 @@ impl StructuredSerializedData {
Transferrable::MessagePort => is_field_empty(&self.ports),
Transferrable::ReadableStream => is_field_empty(&self.ports),
Transferrable::WritableStream => is_field_empty(&self.ports),
+ Transferrable::TransformStream => is_field_empty(&self.ports),
}
}
diff --git a/components/shared/constellation/structured_data/serializable.rs b/components/shared/constellation/structured_data/serializable.rs
index 22370087665..194f0567c51 100644
--- a/components/shared/constellation/structured_data/serializable.rs
+++ b/components/shared/constellation/structured_data/serializable.rs
@@ -88,7 +88,7 @@ impl Clone for BroadcastMsg {
}
/// File-based blob
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FileBlob {
#[ignore_malloc_size_of = "Uuid are hard(not really)"]
id: Uuid,
@@ -164,7 +164,7 @@ impl BroadcastClone for BlobImpl {
}
/// The data backing a DOM Blob.
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct BlobImpl {
/// UUID of the blob.
blob_id: BlobId,
@@ -177,7 +177,7 @@ pub struct BlobImpl {
}
/// Different backends of Blob
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub enum BlobData {
/// File-based blob, whose content lives in the net process
File(FileBlob),
diff --git a/components/shared/constellation/structured_data/transferable.rs b/components/shared/constellation/structured_data/transferable.rs
index 7e4fe0e6d2d..528c1e79e65 100644
--- a/components/shared/constellation/structured_data/transferable.rs
+++ b/components/shared/constellation/structured_data/transferable.rs
@@ -24,9 +24,11 @@ pub enum Transferrable {
ReadableStream,
/// The `WritableStream` interface.
WritableStream,
+ /// The `TransformStream` interface.
+ TransformStream,
}
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
enum MessagePortState {
/// <https://html.spec.whatwg.org/multipage/#detached>
Detached,
@@ -40,7 +42,7 @@ enum MessagePortState {
Disabled(bool),
}
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
/// The data and logic backing the DOM managed MessagePort.
pub struct MessagePortImpl {
/// The current state of the port.
diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs
index c87fa9019ef..e9427fcc719 100644
--- a/components/shared/embedder/lib.rs
+++ b/components/shared/embedder/lib.rs
@@ -13,8 +13,10 @@ pub mod resources;
pub mod user_content_manager;
mod webdriver;
+use std::collections::HashMap;
use std::ffi::c_void;
use std::fmt::{Debug, Display, Error, Formatter};
+use std::hash::Hash;
use std::path::PathBuf;
use std::sync::Arc;
@@ -372,6 +374,12 @@ pub enum EmbedderMsg {
DeviceIntRect,
IpcSender<Option<usize>>,
),
+ /// Inform the embedding layer that a JavaScript evaluation has
+ /// finished with the given result.
+ FinishJavaScriptEvaluation(
+ JavaScriptEvaluationId,
+ Result<JSValue, JavaScriptEvaluationError>,
+ ),
}
impl Debug for EmbedderMsg {
@@ -857,3 +865,59 @@ impl Display for FocusSequenceNumber {
Display::fmt(&self.0, f)
}
}
+
+/// An identifier for a particular JavaScript evaluation that is used to track the
+/// evaluation from the embedding layer to the script layer and then back.
+#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
+pub struct JavaScriptEvaluationId(pub usize);
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+pub enum JSValue {
+ Undefined,
+ Null,
+ Boolean(bool),
+ Number(f64),
+ String(String),
+ Element(String),
+ Frame(String),
+ Window(String),
+ Array(Vec<JSValue>),
+ Object(HashMap<String, JSValue>),
+}
+
+impl From<&WebDriverJSValue> for JSValue {
+ fn from(value: &WebDriverJSValue) -> Self {
+ match value {
+ WebDriverJSValue::Undefined => Self::Undefined,
+ WebDriverJSValue::Null => Self::Null,
+ WebDriverJSValue::Boolean(value) => Self::Boolean(*value),
+ WebDriverJSValue::Int(value) => Self::Number(*value as f64),
+ WebDriverJSValue::Number(value) => Self::Number(*value),
+ WebDriverJSValue::String(value) => Self::String(value.clone()),
+ WebDriverJSValue::Element(web_element) => Self::Element(web_element.0.clone()),
+ WebDriverJSValue::Frame(web_frame) => Self::Frame(web_frame.0.clone()),
+ WebDriverJSValue::Window(web_window) => Self::Window(web_window.0.clone()),
+ WebDriverJSValue::ArrayLike(vector) => {
+ Self::Array(vector.iter().map(Into::into).collect())
+ },
+ WebDriverJSValue::Object(map) => Self::Object(
+ map.iter()
+ .map(|(key, value)| (key.clone(), value.into()))
+ .collect(),
+ ),
+ }
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+pub enum JavaScriptEvaluationError {
+ /// An internal Servo error prevented the JavaSript evaluation from completing properly.
+ /// This indicates a bug in Servo.
+ InternalError,
+ /// The `WebView` on which this evaluation request was triggered is not ready. This might
+ /// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
+ WebViewNotReady,
+ /// The script executed successfully, but Servo could not serialize the JavaScript return
+ /// value into a [`JSValue`].
+ SerializationError,
+}
diff --git a/components/shared/net/request.rs b/components/shared/net/request.rs
index 9c3693316b0..259132b55c4 100644
--- a/components/shared/net/request.rs
+++ b/components/shared/net/request.rs
@@ -8,7 +8,7 @@ use base::id::{PipelineId, WebViewId};
use content_security_policy::{self as csp};
use http::header::{AUTHORIZATION, HeaderName};
use http::{HeaderMap, Method};
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
use malloc_size_of_derive::MallocSizeOf;
use mime::Mime;
use serde::{Deserialize, Serialize};
@@ -156,7 +156,7 @@ pub enum BodySource {
#[derive(Debug, Deserialize, Serialize)]
pub enum BodyChunkResponse {
/// A chunk of bytes.
- Chunk(Vec<u8>),
+ Chunk(IpcSharedMemory),
/// The body is done.
Done,
/// There was an error streaming the body,
diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs
index 748c42400a8..29acc51765c 100644
--- a/components/shared/script/lib.rs
+++ b/components/shared/script/lib.rs
@@ -27,8 +27,8 @@ use crossbeam_channel::{RecvTimeoutError, Sender};
use devtools_traits::ScriptToDevtoolsControlMsg;
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{
- CompositorHitTestResult, FocusSequenceNumber, InputEvent, MediaSessionActionType, Theme,
- ViewportDetails, WebDriverScriptCommand,
+ CompositorHitTestResult, FocusSequenceNumber, InputEvent, JavaScriptEvaluationId,
+ MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand,
};
use euclid::{Rect, Scale, Size2D, UnknownUnit};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
@@ -245,6 +245,9 @@ pub enum ScriptThreadMessage {
/// The compositor scrolled and is updating the scroll states of the nodes in the given
/// pipeline via the Constellation.
SetScrollStates(PipelineId, Vec<ScrollState>),
+ /// Evaluate the given JavaScript and return a result via a corresponding message
+ /// to the Constellation.
+ EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
}
impl fmt::Debug for ScriptThreadMessage {
diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs
index 8c5d4edc4e0..1f526b64240 100644
--- a/components/shared/script_layout/lib.rs
+++ b/components/shared/script_layout/lib.rs
@@ -114,6 +114,7 @@ pub enum LayoutElementType {
HTMLTableRowElement,
HTMLTableSectionElement,
HTMLTextAreaElement,
+ SVGImageElement,
SVGSVGElement,
}
diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs
index 9136e091472..842d9f0dbc2 100644
--- a/components/webdriver_server/actions.rs
+++ b/components/webdriver_server/actions.rs
@@ -18,7 +18,7 @@ use webdriver::actions::{
};
use webdriver::error::{ErrorStatus, WebDriverError};
-use crate::{Handler, wait_for_script_response};
+use crate::{Handler, WebElement, wait_for_script_response};
// Interval between wheelScroll and pointerMove increments in ms, based on common vsync
static POINTERMOVE_INTERVAL: u64 = 17;
@@ -393,41 +393,29 @@ impl Handler {
let (x, y) = match action.origin {
PointerOrigin::Viewport => (x_offset, y_offset),
PointerOrigin::Pointer => (start_x + x_offset, start_y + y_offset),
- PointerOrigin::Element(ref x) => {
- let (sender, receiver) = ipc::channel().unwrap();
- self.browsing_context_script_command(
- WebDriverScriptCommand::GetElementInViewCenterPoint(x.to_string(), sender),
- )
- .unwrap();
- let response = match wait_for_script_response(receiver) {
- Ok(response) => response,
- Err(WebDriverError { error, .. }) => return Err(error),
- };
- let Ok(Some(point)) = response else {
- return Err(ErrorStatus::UnknownError);
- };
- point
+ PointerOrigin::Element(ref web_element) => {
+ self.get_element_origin_relative_coordinates(web_element)?
},
};
// Step 5 - 6
self.check_viewport_bound(x, y)?;
- // Step 9
+ // Step 7
let duration = match action.duration {
Some(duration) => duration,
None => tick_duration,
};
- // Step 10
+ // Step 8
if duration > 0 {
thread::sleep(Duration::from_millis(POINTERMOVE_INTERVAL));
}
- // Step 11
+ // Step 9 - 18
self.perform_pointer_move(source_id, duration, start_x, start_y, x, y, tick_start);
- // Step 12
+ // Step 19
Ok(())
}
@@ -482,6 +470,7 @@ impl Handler {
// Step 7.2
let cmd_msg =
WebDriverCommandMsg::MouseMoveAction(session.webview_id, x as f32, y as f32);
+ //TODO: Need Synchronization here before updating `pointer_input_state`
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
@@ -525,10 +514,13 @@ impl Handler {
};
// Step 3 - 4
- // Get coordinates relative to an origin. Origin must be viewport.
+ // Get coordinates relative to an origin.
let (x, y) = match action.origin {
PointerOrigin::Viewport => (x_offset, y_offset),
- _ => return Err(ErrorStatus::InvalidArgument),
+ PointerOrigin::Pointer => return Err(ErrorStatus::InvalidArgument),
+ PointerOrigin::Element(ref web_element) => {
+ self.get_element_origin_relative_coordinates(web_element)?
+ },
};
// Step 5 - 6
@@ -658,4 +650,24 @@ impl Handler {
Ok(())
}
}
+
+ fn get_element_origin_relative_coordinates(
+ &self,
+ web_element: &WebElement,
+ ) -> Result<(i64, i64), ErrorStatus> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.browsing_context_script_command(WebDriverScriptCommand::GetElementInViewCenterPoint(
+ web_element.to_string(),
+ sender,
+ ))
+ .unwrap();
+ let response = match wait_for_script_response(receiver) {
+ Ok(response) => response,
+ Err(WebDriverError { error, .. }) => return Err(error),
+ };
+ match response? {
+ Some(point) => Ok(point),
+ None => Err(ErrorStatus::UnknownError),
+ }
+ }
}
diff --git a/python/servo/try_parser.py b/python/servo/try_parser.py
index 9a6b31693b0..0d78599c06f 100644
--- a/python/servo/try_parser.py
+++ b/python/servo/try_parser.py
@@ -39,11 +39,12 @@ class JobConfig(object):
unit_tests: bool = False
build_libservo: bool = False
bencher: bool = False
+ build_args: str = ""
wpt_args: str = ""
number_of_wpt_chunks: int = 20
# These are the fields that must match in between two JobConfigs for them to be able to be
# merged. If you modify any of the fields above, make sure to update this line as well.
- merge_compatibility_fields: ClassVar[List[str]] = ['workflow', 'profile', 'wpt_args']
+ merge_compatibility_fields: ClassVar[List[str]] = ['workflow', 'profile', 'wpt_args', 'build_args']
def merge(self, other: JobConfig) -> bool:
"""Try to merge another job with this job. Returns True if merging is successful
@@ -209,7 +210,8 @@ class TestParser(unittest.TestCase):
'build_libservo': False,
'workflow': 'linux',
'wpt': False,
- 'wpt_args': ''
+ 'wpt_args': '',
+ 'build_args': ''
}]
})
@@ -225,7 +227,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': True,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "MacOS (Unit Tests)",
@@ -236,7 +239,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Windows (Unit Tests)",
@@ -247,7 +251,8 @@ class TestParser(unittest.TestCase):
"unit_tests": True,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Android",
@@ -258,7 +263,8 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "OpenHarmony",
@@ -269,7 +275,8 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""
+ "wpt_args": "",
+ 'build_args': ''
},
{
"name": "Lint",
@@ -280,7 +287,9 @@ class TestParser(unittest.TestCase):
"unit_tests": False,
'build_libservo': False,
'bencher': False,
- "wpt_args": ""}
+ "wpt_args": "",
+ 'build_args': ''
+ }
]})
def test_job_merging(self):
@@ -295,7 +304,8 @@ class TestParser(unittest.TestCase):
'build_libservo': False,
'workflow': 'linux',
'wpt': True,
- 'wpt_args': ''
+ 'wpt_args': '',
+ 'build_args': ''
}]
})
@@ -327,6 +337,11 @@ class TestParser(unittest.TestCase):
self.assertFalse(a.merge(b), "Should not merge jobs that run different WPT tests.")
self.assertEqual(a, JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True))
+ a = JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True)
+ b = JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True, build_args="--help")
+ self.assertFalse(a.merge(b), "Should not merge jobs with different build arguments.")
+ self.assertEqual(a, JobConfig("Linux (Unit Tests)", Workflow.LINUX, unit_tests=True))
+
def test_full(self):
self.assertDictEqual(json.loads(Config("full").to_json()),
json.loads(Config("").to_json()))
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index 277c0f4217d..72aed525d96 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -167223,6 +167223,19 @@
{}
]
],
+ "display-contents-inline-002.html": [
+ "f40a34129f348aca37fca83f70598053cf22785b",
+ [
+ null,
+ [
+ [
+ "/css/css-display/display-contents-pass-no-red-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"display-contents-inline-flex-001.html": [
"43b502731aefbaa348671e32171f0e1eb4bca04b",
[
@@ -618423,7 +618436,7 @@
]
],
"table-client-props.html": [
- "4af06d6bf71f0df75d3710ec0906445e943d340d",
+ "2895bebebbf1868ef60f947d230ecca96dd6e85a",
[
null,
{}
diff --git a/tests/wpt/meta/content-security-policy/reporting/report-clips-sample.https.html.ini b/tests/wpt/meta/content-security-policy/reporting/report-clips-sample.https.html.ini
index 783a58399e0..282ea4398ee 100644
--- a/tests/wpt/meta/content-security-policy/reporting/report-clips-sample.https.html.ini
+++ b/tests/wpt/meta/content-security-policy/reporting/report-clips-sample.https.html.ini
@@ -16,6 +16,3 @@
[AsyncGenerator Function constructor is also clipped.]
expected: FAIL
-
- [Trusted Types violation sample is clipped to 40 characters excluded the sink name.]
- expected: FAIL
diff --git a/tests/wpt/meta/fetch/metadata/generated/svg-image.https.sub.html.ini b/tests/wpt/meta/fetch/metadata/generated/svg-image.https.sub.html.ini
index 5d85add7f82..1e547ae5f21 100644
--- a/tests/wpt/meta/fetch/metadata/generated/svg-image.https.sub.html.ini
+++ b/tests/wpt/meta/fetch/metadata/generated/svg-image.https.sub.html.ini
@@ -1,70 +1,69 @@
[svg-image.https.sub.html]
- expected: TIMEOUT
[sec-fetch-site - Same origin no attributes]
- expected: TIMEOUT
+ expected: FAIL
[sec-fetch-site - Cross-site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Cross-Site -> Same Origin no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Cross-Site -> Same-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Cross-Site -> Cross-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Origin -> Same Origin no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Origin -> Same-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Origin -> Cross-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Site -> Same Origin no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Site -> Same-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Same-Site -> Cross-Site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - HTTPS downgrade-upgrade no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode attributes: crossorigin]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode attributes: crossorigin=anonymous]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode attributes: crossorigin=use-credentials]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-dest no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-user no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-storage-access - Cross-site no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-storage-access - Same site no attributes]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/meta/fetch/metadata/generated/svg-image.sub.html.ini b/tests/wpt/meta/fetch/metadata/generated/svg-image.sub.html.ini
index dc3a74db79c..cec7a0548b1 100644
--- a/tests/wpt/meta/fetch/metadata/generated/svg-image.sub.html.ini
+++ b/tests/wpt/meta/fetch/metadata/generated/svg-image.sub.html.ini
@@ -1,55 +1,54 @@
[svg-image.sub.html]
- expected: TIMEOUT
[sec-fetch-site - Not sent to non-trustworthy same-origin destination no attributes]
- expected: TIMEOUT
+ expected: FAIL
[sec-fetch-site - Not sent to non-trustworthy same-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - Not sent to non-trustworthy cross-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode - Not sent to non-trustworthy same-origin destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode - Not sent to non-trustworthy same-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-mode - Not sent to non-trustworthy cross-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-dest - Not sent to non-trustworthy same-origin destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-dest - Not sent to non-trustworthy same-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-dest - Not sent to non-trustworthy cross-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-user - Not sent to non-trustworthy same-origin destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-user - Not sent to non-trustworthy same-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-user - Not sent to non-trustworthy cross-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - HTTPS downgrade (header not sent) no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - HTTPS upgrade no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-site - HTTPS downgrade-upgrade no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-storage-access - Not sent to non-trustworthy same-origin destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-storage-access - Not sent to non-trustworthy same-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
[sec-fetch-storage-access - Not sent to non-trustworthy cross-site destination no attributes]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini
index c94490ae5ee..9cf5b2af86a 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini
@@ -1,13 +1,13 @@
[createImageBitmap-drawImage.html]
expected: ERROR
[createImageBitmap from an OffscreenCanvas resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector HTMLImageElement resized, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from an OffscreenCanvas, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -22,34 +22,34 @@
expected: FAIL
[createImageBitmap from an ImageData scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an OffscreenCanvas scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap SVGImageElement, and drawImage on the created ImageBitmap]
- expected: TIMEOUT
+ expected: FAIL
[createImageBitmap from a bitmap SVGImageElement resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement scaled down, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from a vector SVGImageElement, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageData scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLVideoElement with negative sw/sh, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from a bitmap SVGImageElement scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector SVGImageElement resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap HTMLImageElement scaled up, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -58,10 +58,10 @@
expected: FAIL
[createImageBitmap from a vector SVGImageElement scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap HTMLImageElement scaled down, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -73,16 +73,16 @@
expected: FAIL
[createImageBitmap from a Blob scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageData resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector HTMLImageElement scaled down, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from an ImageData, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement with negative sw/sh, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -91,16 +91,16 @@
expected: FAIL
[createImageBitmap from a vector SVGImageElement scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageBitmap, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a Blob scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap SVGImageElement scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLVideoElement scaled up, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -109,7 +109,7 @@
expected: FAIL
[createImageBitmap from a Blob, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLVideoElement resized, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -118,31 +118,31 @@
expected: FAIL
[createImageBitmap from an ImageBitmap scaled down, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageData with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageBitmap scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageBitmap resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an OffscreenCanvas scaled up, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement scaled up, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from a Blob resized, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLVideoElement from a data URL, and drawImage on the created ImageBitmap]
expected: FAIL
@@ -154,10 +154,10 @@
expected: FAIL
[createImageBitmap from an ImageBitmap with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an OffscreenCanvas with negative sw/sh, and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector HTMLImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html.ini
index f08e8a2918a..0cb93c5abc9 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html.ini
@@ -4,7 +4,7 @@
expected: NOTRUN
[createImageBitmap from a vector SVGImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement imageOrientation: "none", and drawImage on the created ImageBitmap]
expected: FAIL
@@ -16,7 +16,7 @@
expected: FAIL
[createImageBitmap from an OffscreenCanvas imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector HTMLImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap]
expected: FAIL
@@ -25,7 +25,7 @@
expected: FAIL
[createImageBitmap from a Blob imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an HTMLCanvasElement imageOrientation: "flipY", and drawImage on the created ImageBitmap]
expected: FAIL
@@ -34,7 +34,7 @@
expected: FAIL
[createImageBitmap from an ImageData imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap HTMLImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap]
expected: FAIL
@@ -43,7 +43,7 @@
expected: NOTRUN
[createImageBitmap from an ImageBitmap imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a vector HTMLImageElement imageOrientation: "none", and drawImage on the created ImageBitmap]
expected: FAIL
@@ -61,7 +61,7 @@
expected: FAIL
[createImageBitmap from a bitmap SVGImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a bitmap SVGImageElement imageOrientation: "none", and drawImage on the created ImageBitmap]
expected: TIMEOUT
@@ -82,19 +82,19 @@
expected: FAIL
[createImageBitmap from a bitmap SVGImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: TIMEOUT
+ expected: FAIL
[createImageBitmap from a vector SVGImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an OffscreenCanvas imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageData imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from an ImageBitmap imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[createImageBitmap from a Blob imageOrientation: "from-image", and drawImage on the created ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini
index 673fc1e4ffd..aba246039a0 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini
@@ -1,5 +1,5 @@
[createImageBitmap-invalid-args.html]
- expected: ERROR
+ expected: CRASH
[createImageBitmap with a vector HTMLImageElement source and sw set to 0]
expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
index 210d26f7740..d7226bfed74 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
@@ -1,34 +1,34 @@
[createImageBitmap-origin.sub.html]
expected: TIMEOUT
[redirected to cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[redirected to cross-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[unclean HTMLCanvasElement: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[unclean HTMLCanvasElement: origin unclear getImageData]
- expected: NOTRUN
+ expected: FAIL
[cross-origin HTMLVideoElement: origin unclear getImageData]
- expected: NOTRUN
+ expected: FAIL
[cross-origin SVGImageElement: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[cross-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[redirected to same-origin HTMLVideoElement: origin unclear getImageData]
- expected: NOTRUN
+ expected: FAIL
[cross-origin HTMLImageElement: origin unclear 2dContext.drawImage]
expected: FAIL
[cross-origin SVGImageElement: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[cross-origin HTMLImageElement: origin unclear getImageData]
expected: FAIL
@@ -37,28 +37,28 @@
expected: FAIL
[redirected to same-origin HTMLVideoElement: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[unclean ImageBitmap: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[redirected to same-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[redirected to cross-origin HTMLVideoElement: origin unclear getImageData]
- expected: NOTRUN
+ expected: FAIL
[unclean ImageBitmap: origin unclear getImageData]
- expected: NOTRUN
+ expected: FAIL
[unclean HTMLCanvasElement: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[unclean ImageBitmap: origin unclear 2dContext.drawImage]
- expected: NOTRUN
+ expected: FAIL
[cross-origin SVGImageElement: origin unclear getImageData]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-serializable.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-serializable.html.ini
index 7616121487c..4234bcb2133 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-serializable.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-serializable.html.ini
@@ -1,7 +1,6 @@
[createImageBitmap-serializable.html]
- expected: TIMEOUT
[Serialize ImageBitmap created from a vector SVGImageElement]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from an HTMLVideoElement]
expected: FAIL
@@ -13,25 +12,25 @@
expected: FAIL
[Serialize ImageBitmap created from an OffscreenCanvas]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from a vector HTMLImageElement]
expected: FAIL
[Serialize ImageBitmap created from a Blob]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from a bitmap HTMLImageElement]
expected: FAIL
[Serializing a non-origin-clean ImageBitmap throws.]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from an ImageData]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from an ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[Serialize ImageBitmap created from a bitmap SVGImageElement]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini
index 5d2657041d1..cff84fd3a26 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini
@@ -1,22 +1,21 @@
[createImageBitmap-transfer.html]
- expected: ERROR
[Transfer ImageBitmap created from a vector HTMLImageElement]
expected: FAIL
[Transfer ImageBitmap created from an ImageData]
- expected: NOTRUN
+ expected: FAIL
[Transfer ImageBitmap created from a vector SVGImageElement]
- expected: NOTRUN
+ expected: FAIL
[Transfer ImageBitmap created from a Blob]
- expected: NOTRUN
+ expected: FAIL
[Transfer ImageBitmap created from an HTMLCanvasElement]
expected: FAIL
[Transfer ImageBitmap created from an OffscreenCanvas]
- expected: NOTRUN
+ expected: FAIL
[Transfer ImageBitmap created from a bitmap HTMLImageElement]
expected: FAIL
@@ -25,13 +24,13 @@
expected: FAIL
[Transfer ImageBitmap created from a bitmap SVGImageElement]
- expected: TIMEOUT
+ expected: FAIL
[Transfer ImageBitmap created from an ImageBitmap]
- expected: NOTRUN
+ expected: FAIL
[Transfer ImageBitmap created from an HTMLVideoElement]
expected: FAIL
[Transferring a non-origin-clean ImageBitmap throws.]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/meta/html/dom/idlharness.https.html.ini b/tests/wpt/meta/html/dom/idlharness.https.html.ini
index 311e3abaf15..981cd249aa6 100644
--- a/tests/wpt/meta/html/dom/idlharness.https.html.ini
+++ b/tests/wpt/meta/html/dom/idlharness.https.html.ini
@@ -5123,231 +5123,6 @@
[External interface: window.external must inherit property "IsSearchProviderInstalled()" with the proper type]
expected: FAIL
- [SVGElement interface: attribute onabort]
- expected: FAIL
-
- [SVGElement interface: attribute onauxclick]
- expected: FAIL
-
- [SVGElement interface: attribute onbeforeinput]
- expected: FAIL
-
- [SVGElement interface: attribute onbeforematch]
- expected: FAIL
-
- [SVGElement interface: attribute onbeforetoggle]
- expected: FAIL
-
- [SVGElement interface: attribute onblur]
- expected: FAIL
-
- [SVGElement interface: attribute oncancel]
- expected: FAIL
-
- [SVGElement interface: attribute oncanplay]
- expected: FAIL
-
- [SVGElement interface: attribute oncanplaythrough]
- expected: FAIL
-
- [SVGElement interface: attribute onchange]
- expected: FAIL
-
- [SVGElement interface: attribute onclick]
- expected: FAIL
-
- [SVGElement interface: attribute onclose]
- expected: FAIL
-
- [SVGElement interface: attribute oncontextlost]
- expected: FAIL
-
- [SVGElement interface: attribute oncontextmenu]
- expected: FAIL
-
- [SVGElement interface: attribute oncontextrestored]
- expected: FAIL
-
- [SVGElement interface: attribute oncopy]
- expected: FAIL
-
- [SVGElement interface: attribute oncuechange]
- expected: FAIL
-
- [SVGElement interface: attribute oncut]
- expected: FAIL
-
- [SVGElement interface: attribute ondblclick]
- expected: FAIL
-
- [SVGElement interface: attribute ondrag]
- expected: FAIL
-
- [SVGElement interface: attribute ondragend]
- expected: FAIL
-
- [SVGElement interface: attribute ondragenter]
- expected: FAIL
-
- [SVGElement interface: attribute ondragleave]
- expected: FAIL
-
- [SVGElement interface: attribute ondragover]
- expected: FAIL
-
- [SVGElement interface: attribute ondragstart]
- expected: FAIL
-
- [SVGElement interface: attribute ondrop]
- expected: FAIL
-
- [SVGElement interface: attribute ondurationchange]
- expected: FAIL
-
- [SVGElement interface: attribute onemptied]
- expected: FAIL
-
- [SVGElement interface: attribute onended]
- expected: FAIL
-
- [SVGElement interface: attribute onerror]
- expected: FAIL
-
- [SVGElement interface: attribute onfocus]
- expected: FAIL
-
- [SVGElement interface: attribute onformdata]
- expected: FAIL
-
- [SVGElement interface: attribute oninput]
- expected: FAIL
-
- [SVGElement interface: attribute oninvalid]
- expected: FAIL
-
- [SVGElement interface: attribute onkeydown]
- expected: FAIL
-
- [SVGElement interface: attribute onkeypress]
- expected: FAIL
-
- [SVGElement interface: attribute onkeyup]
- expected: FAIL
-
- [SVGElement interface: attribute onload]
- expected: FAIL
-
- [SVGElement interface: attribute onloadeddata]
- expected: FAIL
-
- [SVGElement interface: attribute onloadedmetadata]
- expected: FAIL
-
- [SVGElement interface: attribute onloadstart]
- expected: FAIL
-
- [SVGElement interface: attribute onmousedown]
- expected: FAIL
-
- [SVGElement interface: attribute onmouseenter]
- expected: FAIL
-
- [SVGElement interface: attribute onmouseleave]
- expected: FAIL
-
- [SVGElement interface: attribute onmousemove]
- expected: FAIL
-
- [SVGElement interface: attribute onmouseout]
- expected: FAIL
-
- [SVGElement interface: attribute onmouseover]
- expected: FAIL
-
- [SVGElement interface: attribute onmouseup]
- expected: FAIL
-
- [SVGElement interface: attribute onpaste]
- expected: FAIL
-
- [SVGElement interface: attribute onpause]
- expected: FAIL
-
- [SVGElement interface: attribute onplay]
- expected: FAIL
-
- [SVGElement interface: attribute onplaying]
- expected: FAIL
-
- [SVGElement interface: attribute onprogress]
- expected: FAIL
-
- [SVGElement interface: attribute onratechange]
- expected: FAIL
-
- [SVGElement interface: attribute onreset]
- expected: FAIL
-
- [SVGElement interface: attribute onresize]
- expected: FAIL
-
- [SVGElement interface: attribute onscroll]
- expected: FAIL
-
- [SVGElement interface: attribute onscrollend]
- expected: FAIL
-
- [SVGElement interface: attribute onsecuritypolicyviolation]
- expected: FAIL
-
- [SVGElement interface: attribute onseeked]
- expected: FAIL
-
- [SVGElement interface: attribute onseeking]
- expected: FAIL
-
- [SVGElement interface: attribute onselect]
- expected: FAIL
-
- [SVGElement interface: attribute onslotchange]
- expected: FAIL
-
- [SVGElement interface: attribute onstalled]
- expected: FAIL
-
- [SVGElement interface: attribute onsubmit]
- expected: FAIL
-
- [SVGElement interface: attribute onsuspend]
- expected: FAIL
-
- [SVGElement interface: attribute ontimeupdate]
- expected: FAIL
-
- [SVGElement interface: attribute ontoggle]
- expected: FAIL
-
- [SVGElement interface: attribute onvolumechange]
- expected: FAIL
-
- [SVGElement interface: attribute onwaiting]
- expected: FAIL
-
- [SVGElement interface: attribute onwebkitanimationend]
- expected: FAIL
-
- [SVGElement interface: attribute onwebkitanimationiteration]
- expected: FAIL
-
- [SVGElement interface: attribute onwebkitanimationstart]
- expected: FAIL
-
- [SVGElement interface: attribute onwebkittransitionend]
- expected: FAIL
-
- [SVGElement interface: attribute onwheel]
- expected: FAIL
-
[SVGElement interface: attribute dataset]
expected: FAIL
@@ -5444,9 +5219,6 @@
[CommandEvent interface: attribute command]
expected: FAIL
- [SVGElement interface: attribute oncommand]
- expected: FAIL
-
[CanvasRenderingContext2D interface: attribute lang]
expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
index cacfdf56967..81329bc1635 100644
--- a/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
@@ -1,16 +1,16 @@
[security.pattern.fillStyle.sub.html]
expected: TIMEOUT
[cross-origin SVGImageElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
- expected: TIMEOUT
+ expected: FAIL
[cross-origin HTMLVideoElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
- expected: NOTRUN
+ expected: FAIL
[redirected to cross-origin HTMLVideoElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
- expected: NOTRUN
+ expected: FAIL
[redirected to same-origin HTMLVideoElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
- expected: NOTRUN
+ expected: TIMEOUT
[unclean HTMLCanvasElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
expected: NOTRUN
diff --git a/tests/wpt/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini b/tests/wpt/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini
index 4d4bbb8a39e..5c286c73da4 100644
--- a/tests/wpt/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini
+++ b/tests/wpt/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini
@@ -1,460 +1,16 @@
[event-handler-all-global-events.html]
- [onabort: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onabort: the default value must be null]
- expected: FAIL
-
- [onauxclick: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onauxclick: the default value must be null]
- expected: FAIL
-
- [onblur: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onblur: the default value must be null]
- expected: FAIL
-
- [oncancel: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncancel: the default value must be null]
- expected: FAIL
-
- [oncanplay: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncanplay: the default value must be null]
- expected: FAIL
-
- [oncanplaythrough: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncanplaythrough: the default value must be null]
- expected: FAIL
-
- [onchange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onchange: the default value must be null]
- expected: FAIL
-
- [onclick: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onclick: the default value must be null]
- expected: FAIL
-
- [onclose: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onclose: the default value must be null]
- expected: FAIL
-
- [oncontextlost: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncontextlost: the default value must be null]
- expected: FAIL
-
- [oncontextmenu: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncontextmenu: the default value must be null]
- expected: FAIL
-
- [oncontextrestored: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncontextrestored: the default value must be null]
- expected: FAIL
-
- [oncuechange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncuechange: the default value must be null]
- expected: FAIL
-
- [ondblclick: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondblclick: the default value must be null]
- expected: FAIL
-
- [ondrag: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondrag: the default value must be null]
- expected: FAIL
-
- [ondragend: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondragend: the default value must be null]
- expected: FAIL
-
- [ondragenter: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondragenter: the default value must be null]
- expected: FAIL
-
- [ondragleave: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondragleave: the default value must be null]
- expected: FAIL
-
- [ondragover: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondragover: the default value must be null]
- expected: FAIL
-
- [ondragstart: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondragstart: the default value must be null]
- expected: FAIL
-
- [ondrop: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondrop: the default value must be null]
- expected: FAIL
-
- [ondurationchange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ondurationchange: the default value must be null]
- expected: FAIL
-
- [onemptied: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onemptied: the default value must be null]
- expected: FAIL
-
- [onended: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onended: the default value must be null]
- expected: FAIL
-
- [onfocus: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onfocus: the default value must be null]
- expected: FAIL
-
- [onformdata: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onformdata: the default value must be null]
- expected: FAIL
-
- [oninput: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oninput: the default value must be null]
- expected: FAIL
-
- [oninvalid: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oninvalid: the default value must be null]
- expected: FAIL
-
- [onkeydown: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onkeydown: the default value must be null]
- expected: FAIL
-
- [onkeypress: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onkeypress: the default value must be null]
- expected: FAIL
-
- [onkeyup: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onkeyup: the default value must be null]
- expected: FAIL
-
- [onload: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onload: the default value must be null]
- expected: FAIL
-
- [onloadeddata: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onloadeddata: the default value must be null]
- expected: FAIL
-
- [onloadedmetadata: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onloadedmetadata: the default value must be null]
- expected: FAIL
-
- [onloadstart: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onloadstart: the default value must be null]
- expected: FAIL
-
- [onmousedown: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmousedown: the default value must be null]
- expected: FAIL
-
- [onmouseenter: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmouseenter: the default value must be null]
- expected: FAIL
-
- [onmouseleave: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmouseleave: the default value must be null]
- expected: FAIL
-
- [onmousemove: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmousemove: the default value must be null]
- expected: FAIL
-
- [onmouseout: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmouseout: the default value must be null]
- expected: FAIL
-
- [onmouseover: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmouseover: the default value must be null]
- expected: FAIL
-
- [onmouseup: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onmouseup: the default value must be null]
- expected: FAIL
-
- [onpause: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onpause: the default value must be null]
- expected: FAIL
-
- [onplay: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onplay: the default value must be null]
- expected: FAIL
-
- [onplaying: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onplaying: the default value must be null]
- expected: FAIL
-
- [onprogress: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onprogress: the default value must be null]
- expected: FAIL
-
- [onratechange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onratechange: the default value must be null]
- expected: FAIL
-
- [onreset: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onreset: the default value must be null]
- expected: FAIL
-
- [onresize: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onresize: the default value must be null]
- expected: FAIL
-
- [onscroll: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onscroll: the default value must be null]
- expected: FAIL
-
- [onsecuritypolicyviolation: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onsecuritypolicyviolation: the default value must be null]
- expected: FAIL
-
- [onseeked: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onseeked: the default value must be null]
- expected: FAIL
-
- [onseeking: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onseeking: the default value must be null]
- expected: FAIL
-
- [onselect: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onselect: the default value must be null]
- expected: FAIL
-
- [onslotchange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onslotchange: the default value must be null]
- expected: FAIL
-
- [onstalled: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onstalled: the default value must be null]
- expected: FAIL
-
- [onsubmit: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onsubmit: the default value must be null]
- expected: FAIL
-
- [onsuspend: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onsuspend: the default value must be null]
- expected: FAIL
-
- [ontimeupdate: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ontimeupdate: the default value must be null]
- expected: FAIL
-
- [ontoggle: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [ontoggle: the default value must be null]
- expected: FAIL
-
- [onvolumechange: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onvolumechange: the default value must be null]
- expected: FAIL
-
- [onwaiting: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwaiting: the default value must be null]
- expected: FAIL
-
- [onwebkitanimationend: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwebkitanimationend: the default value must be null]
- expected: FAIL
-
[onwebkitanimationend: the content attribute must execute when an event is dispatched]
expected: FAIL
- [onwebkitanimationiteration: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwebkitanimationiteration: the default value must be null]
- expected: FAIL
-
[onwebkitanimationiteration: the content attribute must execute when an event is dispatched]
expected: FAIL
- [onwebkitanimationstart: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwebkitanimationstart: the default value must be null]
- expected: FAIL
-
[onwebkitanimationstart: the content attribute must execute when an event is dispatched]
expected: FAIL
- [onwebkittransitionend: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwebkittransitionend: the default value must be null]
- expected: FAIL
-
[onwebkittransitionend: the content attribute must execute when an event is dispatched]
expected: FAIL
- [onwheel: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onwheel: the default value must be null]
- expected: FAIL
-
- [onbeforeinput: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onbeforeinput: the default value must be null]
- expected: FAIL
-
- [onbeforematch: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onbeforematch: the default value must be null]
- expected: FAIL
-
- [onscrollend: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onscrollend: the default value must be null]
- expected: FAIL
-
- [oncopy: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncopy: the default value must be null]
- expected: FAIL
-
- [oncut: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncut: the default value must be null]
- expected: FAIL
-
- [onpaste: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onpaste: the default value must be null]
- expected: FAIL
-
- [onbeforetoggle: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [onbeforetoggle: the default value must be null]
- expected: FAIL
-
[onwebkitanimationend: dispatching an Event at a <meta> element must trigger element.onwebkitanimationend]
expected: FAIL
@@ -466,9 +22,3 @@
[onwebkittransitionend: dispatching an Event at a <meta> element must trigger element.onwebkittransitionend]
expected: FAIL
-
- [oncommand: must be on the appropriate locations for GlobalEventHandlers]
- expected: FAIL
-
- [oncommand: the default value must be null]
- expected: FAIL
diff --git a/tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini b/tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini
deleted file mode 100644
index a2502281be7..00000000000
--- a/tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[transfer-with-messageport.window.html]
- [Transferring a MessagePort with a TransformStream should set `.ports`]
- expected: FAIL
-
- [Transferring a MessagePort with a TransformStream should set `.ports`, advanced]
- expected: FAIL
-
- [Transferring a MessagePort with multiple streams should set `.ports`]
- expected: FAIL
diff --git a/tests/wpt/meta/streams/transferable/transform-stream.html.ini b/tests/wpt/meta/streams/transferable/transform-stream.html.ini
index af9a1d42ae7..a5097f80874 100644
--- a/tests/wpt/meta/streams/transferable/transform-stream.html.ini
+++ b/tests/wpt/meta/streams/transferable/transform-stream.html.ini
@@ -1,6 +1,3 @@
[transform-stream.html]
- [window.postMessage should be able to transfer a TransformStream]
- expected: FAIL
-
[piping through transferred transforms should work]
expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini b/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini
deleted file mode 100644
index 8ed1a875db3..00000000000
--- a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[HTMLElement-generic.html]
- [TT enabled: div.innerHTML\n = String on a\n connected element\n ]
- expected: FAIL
-
- [TT enabled: div.innerHTML\n = String on a\n non-connected element\n ]
- expected: FAIL
-
- [TT enabled: iframe.srcdoc\n = String on a\n connected element\n ]
- expected: FAIL
-
- [TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n ]
- expected: FAIL
-
- [TT enabled: div.innerHTML\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
- expected: FAIL
-
- [TT enabled: div.innerHTML\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
- expected: FAIL
-
- [TT enabled: iframe.srcdoc\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
- expected: FAIL
-
- [TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html.ini
deleted file mode 100644
index 1306015ff46..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[block-string-assignment-to-Element-insertAdjacentHTML.html]
- [`insertAdjacentHTML(string)` throws.]
- expected: FAIL
-
- [`insertAdjacentHTML(string)` still throws TypeError when position invalid.]
- expected: FAIL
-
- [`insertAdjacentHTML(null)` throws.]
- expected: FAIL
-
- [`insertAdjacentHTML(string)` assigned via default policy (successful HTML transformation).]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-outerHTML.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-outerHTML.html.ini
deleted file mode 100644
index e5abefcc766..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-outerHTML.html.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[block-string-assignment-to-Element-outerHTML.html]
- [`outerHTML = string` throws.]
- expected: FAIL
-
- [`outerHTML = string` throws TypeError even when parent is a document.]
- expected: FAIL
-
- [`outerHTML = null` throws.]
- expected: FAIL
-
- [`outerHTML = string` assigned via default policy (successful HTML transformation).]
- expected: FAIL
-
- [`outerHTML = null` assigned via default policy does not throw]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setAttribute.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setAttribute.html.ini
index 7ad472ef325..0df917b86be 100644
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setAttribute.html.ini
+++ b/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setAttribute.html.ini
@@ -20,9 +20,6 @@
[div.onclick's mutationobservers receive the default policy's value.]
expected: FAIL
- [iframe.srcdoc accepts string and null after default policy was created.]
- expected: FAIL
-
[div.onclick accepts string and null after default policy was created.]
expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html.ini
deleted file mode 100644
index e6b59ba6714..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[block-string-assignment-to-Element-setHTMLUnsafe.html]
- [`element.setHTMLUnsafe(string)` throws.]
- expected: FAIL
-
- [`element.setHTMLUnsafe(null)` throws.]
- expected: FAIL
-
- [`element.setHTMLUnsafe(string)` assigned via default policy (successful HTML transformation).]
- expected: FAIL
-
- [`element.setHTMLUnsafe(string)` assigned via default policy does not throw]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini
deleted file mode 100644
index ed3a70b31ab..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[block-string-assignment-to-HTMLElement-generic.html]
- [div.innerHTML accepts only TrustedHTML]
- expected: FAIL
-
- [iframe.srcdoc accepts only TrustedHTML]
- expected: FAIL
-
- [div.innerHTML accepts string and null after default policy was created]
- expected: FAIL
-
- [iframe.srcdoc accepts string and null after default policy was created]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLIFrameElement-srcdoc.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLIFrameElement-srcdoc.html.ini
deleted file mode 100644
index e7747a96001..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLIFrameElement-srcdoc.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[block-string-assignment-to-HTMLIFrameElement-srcdoc.html]
- [`iframe.srcdoc = string` throws.]
- expected: FAIL
-
- [`iframe.srcdoc = null` throws.]
- expected: FAIL
-
- [`iframe.srcdoc = string` assigned via default policy (successful HTML transformation).]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini
deleted file mode 100644
index 1e9f6e44f44..00000000000
--- a/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[block-string-assignment-to-text-and-url-sinks.html]
- [Setting HTMLDivElement.innerHTML to a plain string]
- expected: FAIL
-
- [Setting HTMLScriptElement.innerHTML to a plain string]
- expected: FAIL
-
- [Setting SVGScriptElement.innerHTML to a plain string]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/default-policy.html.ini b/tests/wpt/meta/trusted-types/default-policy.html.ini
deleted file mode 100644
index cf57031ddbe..00000000000
--- a/tests/wpt/meta/trusted-types/default-policy.html.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[default-policy.html]
- expected: OK
- [Count SecurityPolicyViolation events.]
- expected: FAIL
-
- [div.innerHTML no default policy]
- expected: FAIL
-
- [div.innerHTML default]
- expected: FAIL
-
- [div.innerHTML null]
- expected: FAIL
-
- [div.innerHTML throw]
- expected: FAIL
-
- [div.innerHTML undefined]
- expected: FAIL
-
- [div.innerHTML typeerror]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/empty-default-policy.html.ini b/tests/wpt/meta/trusted-types/empty-default-policy.html.ini
deleted file mode 100644
index c3f34522557..00000000000
--- a/tests/wpt/meta/trusted-types/empty-default-policy.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[empty-default-policy.html]
- expected: OK
- [Count SecurityPolicyViolation events.]
- expected: FAIL
-
- [div.innerHTML default]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html.ini b/tests/wpt/meta/trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html.ini
index df0dfe485ed..63099aaaaff 100644
--- a/tests/wpt/meta/trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html.ini
+++ b/tests/wpt/meta/trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html.ini
@@ -1,6 +1,3 @@
[require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html]
- [Setting innerHTML on a node inserted by the parser.]
- expected: FAIL
-
[Setting innerHTML on a node adopted from a subframe.]
expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini b/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini
deleted file mode 100644
index 39ec281d5f2..00000000000
--- a/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[require-trusted-types-for-report-only.html]
- [Require trusted types for 'script' block create HTML.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini b/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini
deleted file mode 100644
index 38d5f9eb35a..00000000000
--- a/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[require-trusted-types-for.html]
- [Require trusted types for 'script' block create HTML.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html.ini b/tests/wpt/meta/trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html.ini
index 57cd759f8bf..d3218647e91 100644
--- a/tests/wpt/meta/trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html.ini
+++ b/tests/wpt/meta/trusted-types/should-sink-type-mismatch-violation-be-blocked-by-csp-001.html.ini
@@ -1,20 +1,5 @@
[should-sink-type-mismatch-violation-be-blocked-by-csp-001.html]
expected: TIMEOUT
- [Multiple enforce require-trusted-types-for directives.]
- expected: FAIL
-
- [Multiple report-only require-trusted-types-for directives.]
- expected: FAIL
-
- [One violated report-only require-trusted-types-for directive followed by multiple enforce directives]
- expected: FAIL
-
- [One violated enforce require-trusted-types-for directive followed by multiple report-only directives]
- expected: FAIL
-
- [Mixing enforce and report-only require-trusted-types-for directives.]
- expected: FAIL
-
[directive "require-trusted-types-for 'script'%09'script'%0A'script'%0C'script'%0D'script'%20'script'" (required-ascii-whitespace)]
expected: TIMEOUT
@@ -33,9 +18,6 @@
[directive "require-trusted-types-for unquoted-invalid 'script' also-unquoted-invalid (unknown sink group)]
expected: NOTRUN
- [directive "require-trusted-types-for 'invalid'%09'script'" (required-ascii-whitespace)]
- expected: FAIL
-
[directive "require-trusted-types-for 'invalid'%0A%20'script'" (required-ascii-whitespace)]
expected: TIMEOUT
diff --git a/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini b/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini
deleted file mode 100644
index cca7dc42f2b..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[trusted-types-createHTMLDocument.html]
- [Trusted Type instances created in the main doc can be used. (document)]
- expected: FAIL
-
- [Trusted Type instances created in the main doc can be used. (createHTMLDocument)]
- expected: FAIL
-
- [Trusted Type instances created in the main doc can be used. (DOMParser)]
- expected: FAIL
-
- [Trusted Type instances created in the main doc can be used. (XHR)]
- expected: FAIL
-
- [Default policy applies. (document)]
- expected: FAIL
-
- [Default policy applies. (createHTMLDocument)]
- expected: FAIL
-
- [Default policy applies. (DOMParser)]
- expected: FAIL
-
- [Default policy applies. (XHR)]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini b/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini
deleted file mode 100644
index 253b126c18f..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[trusted-types-report-only.html]
- [Trusted Type violation report-only: assign string to html]
- expected: FAIL
-
- [Trusted Type violation report-only: assign string to script content]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-innerHTML.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-innerHTML.html.ini
deleted file mode 100644
index ae31cf41b62..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-innerHTML.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-Element-innerHTML.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-insertAdjacentHTML.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-insertAdjacentHTML.html.ini
deleted file mode 100644
index ea9822131e6..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-insertAdjacentHTML.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-Element-insertAdjacentHTML.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-outerHTML.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-outerHTML.html.ini
deleted file mode 100644
index ccf4d385ddc..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-outerHTML.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-Element-outerHTML.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-setHTMLUnsafe.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-setHTMLUnsafe.html.ini
deleted file mode 100644
index a288f0fc52b..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-Element-setHTMLUnsafe.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-Element-setHTMLUnsafe.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html.ini
deleted file mode 100644
index 9f2a73c0900..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement-innerHTML.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement-innerHTML.html.ini
deleted file mode 100644
index 74b6b2803cd..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement-innerHTML.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-HTMLScriptElement-innerHTML.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-SVGScriptElement-innerHTML.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-SVGScriptElement-innerHTML.html.ini
deleted file mode 100644
index 55b972f6001..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-SVGScriptElement-innerHTML.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-reporting-for-SVGScriptElement-innerHTML.html]
- [Violation report for plain string.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-sandbox-allow-scripts.html.ini b/tests/wpt/meta/trusted-types/trusted-types-sandbox-allow-scripts.html.ini
deleted file mode 100644
index 7053da4f6d0..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-sandbox-allow-scripts.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[trusted-types-sandbox-allow-scripts.html]
- [Default Trusted Types policy in a sandboxed page with allow-scripts.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-source-file-path.html.ini b/tests/wpt/meta/trusted-types/trusted-types-source-file-path.html.ini
deleted file mode 100644
index a05cfef0db5..00000000000
--- a/tests/wpt/meta/trusted-types/trusted-types-source-file-path.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[trusted-types-source-file-path.html]
- [same-document script]
- expected: FAIL
-
- [same-origin script]
- expected: FAIL
-
- [cross-origin script]
- expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 033a13106ac..2797b63f2ae 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -13582,7 +13582,7 @@
]
],
"interfaces.https.html": [
- "72918e837726b58740a491a9223eeeb625055ae5",
+ "eee8c799727b91e00b512795756b693a5f121f86",
[
null,
{}
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
index 72918e83772..eee8c799727 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
@@ -315,6 +315,7 @@ test_interfaces([
"SubtleCrypto",
"SVGElement",
"SVGGraphicsElement",
+ "SVGImageElement",
"SVGRect",
"SVGSVGElement",
"Text",
diff --git a/tests/wpt/tests/css/css-display/display-contents-inline-002.html b/tests/wpt/tests/css/css-display/display-contents-inline-002.html
new file mode 100644
index 00000000000..f40a34129f3
--- /dev/null
+++ b/tests/wpt/tests/css/css-display/display-contents-inline-002.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Display: display:contents in inline layout should affect style of descendants</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
+<link rel="match" href="display-contents-pass-no-red-ref.html">
+<style>
+ #contents {
+ display: contents;
+ color: black;
+ }
+ .red { color: red; }
+</style>
+<p>You should see the word PASS and no red below.</p>
+<span>
+ P<span class="red"><div id="contents">AS</div></span>S
+</span>
diff --git a/tests/wpt/tests/css/cssom-view/table-client-props.html b/tests/wpt/tests/css/cssom-view/table-client-props.html
index 4af06d6bf71..2895bebebbf 100644
--- a/tests/wpt/tests/css/cssom-view/table-client-props.html
+++ b/tests/wpt/tests/css/cssom-view/table-client-props.html
@@ -43,6 +43,19 @@
<tr><td>`,
26, 34,
"Table with collapsed border" ],
+ [ `<div style="display: flex">
+ <table style="width: 20px; height: 30px;
+ border-width: 1px 2px 3px 4px; border-style: solid;
+ border-collapse: separate; box-sizing: content-box">`,
+ 26, 34,
+ "Flex-level table with separated border" ],
+ [ `<div style="display: flex">
+ <table style="width: 20px; height: 30px;
+ border-width: 2px 4px 6px 8px; border-style: solid;
+ border-collapse: collapse; box-sizing: content-box">
+ <tr><td>`,
+ 26, 34,
+ "Flex-level table with collapsed border" ],
[ `<table>
<caption style="width: 40px; height: 50px; padding: 1px 2px 3px 4px">`,
46, 54,