aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Cargo.lock31
-rw-r--r--Cargo.toml2
-rw-r--r--components/compositing/compositor.rs24
-rw-r--r--components/compositing/tracing.rs1
-rw-r--r--components/compositing/webview_renderer.rs16
-rw-r--r--components/constellation/constellation.rs6
-rw-r--r--components/constellation/sandboxing.rs1
-rw-r--r--components/fonts/Cargo.toml1
-rw-r--r--components/fonts/font_store.rs10
-rw-r--r--components/fonts/font_template.rs18
-rw-r--r--components/fonts/system_font_service.rs45
-rw-r--r--components/fonts/tests/font.rs13
-rw-r--r--components/fonts/tests/font_context.rs1
-rw-r--r--components/layout/display_list/mod.rs2
-rw-r--r--components/layout/fragment_tree/box_fragment.rs9
-rw-r--r--components/layout/layout_impl.rs9
-rw-r--r--components/layout/table/construct.rs17
-rw-r--r--components/layout/table/layout.rs8
-rw-r--r--components/layout/table/mod.rs12
-rw-r--r--components/malloc_size_of/lib.rs41
-rw-r--r--components/pixels/lib.rs7
-rw-r--r--components/script/dom/bindings/cell.rs7
-rw-r--r--components/script/dom/clipboard.rs146
-rw-r--r--components/script/dom/clipboarditem.rs8
-rw-r--r--components/script/dom/document.rs12
-rw-r--r--components/script/dom/element.rs2
-rw-r--r--components/script/dom/event.rs29
-rw-r--r--components/script/dom/eventsource.rs2
-rw-r--r--components/script/dom/globalscope.rs46
-rw-r--r--components/script/dom/htmlimageelement.rs10
-rw-r--r--components/script/dom/htmllinkelement.rs4
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/htmlscriptelement.rs10
-rw-r--r--components/script/dom/htmlstyleelement.rs18
-rw-r--r--components/script/dom/htmlvideoelement.rs2
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/node.rs14
-rw-r--r--components/script/dom/notification.rs2
-rw-r--r--components/script/dom/readablestreamdefaultcontroller.rs2
-rw-r--r--components/script/dom/readablestreamgenericreader.rs1
-rw-r--r--components/script/dom/securitypolicyviolationevent.rs11
-rw-r--r--components/script/dom/servoparser/html.rs41
-rw-r--r--components/script/dom/servoparser/mod.rs3
-rw-r--r--components/script/dom/transformstream.rs999
-rw-r--r--components/script/dom/transformstreamdefaultcontroller.rs420
-rw-r--r--components/script/dom/trustedtypepolicyfactory.rs4
-rw-r--r--components/script/dom/underlyingsourcecontainer.rs18
-rw-r--r--components/script/dom/websocket.rs2
-rw-r--r--components/script/dom/window.rs28
-rw-r--r--components/script/dom/writablestream.rs3
-rw-r--r--components/script/dom/writablestreamdefaultcontroller.rs31
-rw-r--r--components/script/dom/xmlhttprequest.rs2
-rw-r--r--components/script/fetch.rs2
-rw-r--r--components/script/layout_image.rs2
-rw-r--r--components/script/script_module.rs2
-rw-r--r--components/script/script_runtime.rs2
-rw-r--r--components/script/script_thread.rs3
-rw-r--r--components/script/security_manager.rs23
-rw-r--r--components/script/stylesheet_loader.rs2
-rw-r--r--components/script/webdriver_handlers.rs74
-rw-r--r--components/script_bindings/codegen/Bindings.conf2
-rw-r--r--components/script_bindings/conversions.rs6
-rw-r--r--components/script_bindings/webidls/Clipboard.webidl2
-rw-r--r--components/script_bindings/webidls/TransformStream.webidl18
-rw-r--r--components/script_bindings/webidls/TransformStreamDefaultController.webidl15
-rw-r--r--components/script_bindings/webidls/Transformer.webidl22
-rw-r--r--components/script_bindings/webidls/Window.webidl4
-rw-r--r--components/servo/lib.rs6
-rw-r--r--components/shared/compositing/lib.rs5
-rw-r--r--components/shared/embedder/input_events.rs7
-rw-r--r--components/shared/embedder/webdriver.rs2
-rw-r--r--components/shared/profile/mem.rs6
-rw-r--r--components/url/lib.rs2
-rw-r--r--components/webdriver_server/actions.rs243
-rw-r--r--components/webdriver_server/lib.rs50
-rw-r--r--components/webgl/Cargo.toml1
-rw-r--r--components/webgl/webgl_thread.rs23
-rw-r--r--python/requirements.txt3
-rw-r--r--python/servo/devtools_tests.py150
-rw-r--r--python/servo/devtools_tests/sources/classic.js1
-rw-r--r--python/servo/devtools_tests/sources/module.js2
-rw-r--r--python/servo/devtools_tests/sources/test.html11
-rw-r--r--python/servo/devtools_tests/sources/worker.js1
-rw-r--r--python/servo/testing_commands.py9
-rw-r--r--tests/wpt/include.ini2
-rw-r--r--tests/wpt/meta/MANIFEST.json9
-rw-r--r--tests/wpt/meta/clipboard-apis/idlharness.https.window.js.ini6
-rw-r--r--tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.http.html.ini9
-rw-r--r--tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.https.html.ini9
-rw-r--r--tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.http.html.ini9
-rw-r--r--tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.https.html.ini9
-rw-r--r--tests/wpt/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini13
-rw-r--r--tests/wpt/meta/content-security-policy/reporting/report-original-url.sub.html.ini6
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-eval.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html.ini12
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/linenumber.tentative.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html.ini8
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample.html.ini14
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-data-scheme.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/targeting.html.ini5
-rw-r--r--tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-attr-allowed.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-src-allowed.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/inline-style-blocked.sub.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-hash-case-insensitive.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-none-blocked.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini7
-rw-r--r--tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini6
-rw-r--r--tests/wpt/meta/fetch/metadata/report.https.sub.html.ini10
-rw-r--r--tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini3
-rw-r--r--tests/wpt/meta/streams/transferable/transform-stream-members.any.js.ini4
-rw-r--r--tests/wpt/meta/streams/transferable/transform-stream.html.ini9
-rw-r--r--tests/wpt/meta/streams/transferable/writable-stream.html.ini3
-rw-r--r--tests/wpt/meta/streams/transform-streams/backpressure.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/cancel.any.js.ini32
-rw-r--r--tests/wpt/meta/streams/transform-streams/errors.any.js.ini32
-rw-r--r--tests/wpt/meta/streams/transform-streams/flush.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/general.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/lipfuzz.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/patched-global.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/properties.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/reentrant-strategies.any.js.ini23
-rw-r--r--tests/wpt/meta/streams/transform-streams/strategies.any.js.ini24
-rw-r--r--tests/wpt/meta/streams/transform-streams/terminate.any.js.ini23
-rw-r--r--tests/wpt/meta/trusted-types/default-policy.html.ini4
-rw-r--r--tests/wpt/meta/trusted-types/empty-default-policy.html.ini4
-rw-r--r--tests/wpt/meta/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html.ini3
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/element_click/scroll_into_view.py.ini20
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/element_send_keys/form_controls.py.ini3
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/element_send_keys/scroll_into_view.py.ini3
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/execute_async_script/collections.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/execute_script/collections.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini12
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/perform.py.ini9
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse.py.ini14
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py.ini42
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini21
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_pen.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_touch.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/sequence.py.ini3
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/perform_actions/wheel.py.ini9
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch_webelement.py.ini6
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/screenshot.py.ini9
-rw-r--r--tests/wpt/meta/webdriver/tests/classic/take_screenshot/iframe.py.ini3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json4
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.https.html2
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.worker.js2
-rw-r--r--tests/wpt/tests/content-security-policy/img-src/icon-blocked.sub.html1
-rw-r--r--tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html24
-rw-r--r--tests/wpt/webgl/meta/conformance/context/premultiplyalpha-test.html.ini8
174 files changed, 2978 insertions, 694 deletions
diff --git a/.gitignore b/.gitignore
index 73c2fce6cda..630eb63b9bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,9 @@ webrender-captures/
Session.vim
Sessionx.vim
+# Zed
+/.zed
+
/unminified-js
/unminified-css
diff --git a/Cargo.lock b/Cargo.lock
index d18aa44ad35..90bb55247c1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -442,9 +442,9 @@ dependencies = [
[[package]]
name = "backtrace"
-version = "0.3.74"
+version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
@@ -1065,7 +1065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -2194,6 +2194,7 @@ dependencies = [
"net_traits",
"num-traits",
"parking_lot",
+ "profile_traits",
"range",
"serde",
"servo_allocator",
@@ -4252,14 +4253,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
]
[[package]]
name = "libm"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a25169bd5913a4b437588a7e3d127cd6e90127b60e0ffbd834a38f1599e016b8"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
@@ -6167,9 +6168,12 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.11.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+dependencies = [
+ "zeroize",
+]
[[package]]
name = "rustls-webpki"
@@ -8478,9 +8482,9 @@ dependencies = [
[[package]]
name = "web_atoms"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee"
+checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e"
dependencies = [
"phf",
"phf_codegen",
@@ -8553,6 +8557,7 @@ dependencies = [
"glow",
"half",
"ipc-channel",
+ "itertools 0.14.0",
"log",
"pixels",
"snapshot",
@@ -8859,7 +8864,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -9259,9 +9264,9 @@ dependencies = [
[[package]]
name = "winnow"
-version = "0.7.9"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
+checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]
diff --git a/Cargo.toml b/Cargo.toml
index b7ba61f2145..52f84878e14 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -115,7 +115,7 @@ rayon = "1"
regex = "1.11"
rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12"] }
rustls-pemfile = "2.0"
-rustls-pki-types = "1.11"
+rustls-pki-types = "1.12"
script_layout_interface = { path = "components/shared/script_layout" }
script_traits = { path = "components/shared/script" }
selectors = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 41286a2760a..b1669277ba1 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -26,9 +26,9 @@ use crossbeam_channel::{Receiver, Sender};
use dpi::PhysicalSize;
use embedder_traits::{
CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ShutdownState,
- TouchEventType, UntrustedNodeAddress, ViewportDetails,
+ TouchEventType, UntrustedNodeAddress, ViewportDetails, WheelDelta, WheelEvent, WheelMode,
};
-use euclid::{Point2D, Rect, Scale, Size2D, Transform3D};
+use euclid::{Point2D, Rect, Scale, Size2D, Transform3D, Vector2D};
use fnv::FnvHashMap;
use ipc_channel::ipc::{self, IpcSharedMemory};
use libc::c_void;
@@ -646,6 +646,26 @@ impl IOCompositor {
.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
},
+ CompositorMsg::WebDriverWheelScrollEvent(webview_id, x, y, delta_x, delta_y) => {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
+ warn!("Handling input event for unknown webview: {webview_id}");
+ return;
+ };
+ let delta = WheelDelta {
+ x: delta_x,
+ y: delta_y,
+ z: 0.0,
+ mode: WheelMode::DeltaPixel,
+ };
+ let dppx = webview_renderer.device_pixels_per_page_pixel();
+ let point = dppx.transform_point(Point2D::new(x, y));
+ let scroll_delta =
+ dppx.transform_vector(Vector2D::new(delta_x as f32, delta_y as f32));
+ webview_renderer
+ .dispatch_input_event(InputEvent::Wheel(WheelEvent { delta, point }));
+ webview_renderer.on_webdriver_wheel_action(scroll_delta, point);
+ },
+
CompositorMsg::SendInitialTransaction(pipeline) => {
let mut txn = Transaction::new();
txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default()));
diff --git a/components/compositing/tracing.rs b/components/compositing/tracing.rs
index ae7338106d0..a8bb8b42bb8 100644
--- a/components/compositing/tracing.rs
+++ b/components/compositing/tracing.rs
@@ -42,6 +42,7 @@ mod from_constellation {
Self::LoadComplete(..) => target!("LoadComplete"),
Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"),
Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"),
+ Self::WebDriverWheelScrollEvent(..) => target!("WebDriverWheelScrollEvent"),
Self::SendInitialTransaction(..) => target!("SendInitialTransaction"),
Self::SendScrollNode(..) => target!("SendScrollNode"),
Self::SendDisplayList { .. } => target!("SendDisplayList"),
diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs
index 614ef0ff4c3..f76dc68013d 100644
--- a/components/compositing/webview_renderer.rs
+++ b/components/compositing/webview_renderer.rs
@@ -726,6 +726,22 @@ impl WebViewRenderer {
}));
}
+ /// Push scroll pending event when receiving wheel action from webdriver
+ pub(crate) fn on_webdriver_wheel_action(
+ &mut self,
+ scroll_delta: Vector2D<f32, DevicePixel>,
+ point: Point2D<f32, DevicePixel>,
+ ) {
+ if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
+ return;
+ }
+
+ let scroll_location =
+ ScrollLocation::Delta(LayoutVector2D::from_untyped(scroll_delta.to_untyped()));
+ let cursor = DeviceIntPoint::new(point.x as i32, point.y as i32);
+ self.on_scroll_window_event(scroll_location, cursor)
+ }
+
pub(crate) fn process_pending_scroll_events(&mut self, compositor: &mut IOCompositor) {
if self.pending_scroll_zoom_events.is_empty() {
return;
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index f3a15d7708d..e493a97d184 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -4783,6 +4783,12 @@ where
self.compositor_proxy
.send(CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y));
},
+ WebDriverCommandMsg::WheelScrollAction(webview, x, y, delta_x, delta_y) => {
+ self.compositor_proxy
+ .send(CompositorMsg::WebDriverWheelScrollEvent(
+ webview, x, y, delta_x, delta_y,
+ ));
+ },
WebDriverCommandMsg::TakeScreenshot(webview_id, rect, response_sender) => {
self.compositor_proxy.send(CompositorMsg::CreatePng(
webview_id,
diff --git a/components/constellation/sandboxing.rs b/components/constellation/sandboxing.rs
index 3738b4f288b..b4c6e7a9a39 100644
--- a/components/constellation/sandboxing.rs
+++ b/components/constellation/sandboxing.rs
@@ -159,6 +159,7 @@ pub fn spawn_multiprocess(content: UnprivilegedContent) -> Result<Process, Error
let mut child_process = process::Command::new(path_to_self);
setup_common(&mut child_process, token);
+ #[allow(clippy::zombie_processes)]
let child = child_process
.spawn()
.expect("Failed to start unsandboxed child process!");
diff --git a/components/fonts/Cargo.toml b/components/fonts/Cargo.toml
index 2323cb1b240..ce51a9f9112 100644
--- a/components/fonts/Cargo.toml
+++ b/components/fonts/Cargo.toml
@@ -38,6 +38,7 @@ memmap2 = { workspace = true }
net_traits = { workspace = true }
num-traits = { workspace = true }
parking_lot = { workspace = true }
+profile_traits = { workspace = true }
range = { path = "../range" }
serde = { workspace = true }
servo_arc = { workspace = true }
diff --git a/components/fonts/font_store.rs b/components/fonts/font_store.rs
index 826be947672..0099c56c266 100644
--- a/components/fonts/font_store.rs
+++ b/components/fonts/font_store.rs
@@ -5,8 +5,8 @@
use std::collections::HashMap;
use std::sync::Arc;
-use atomic_refcell::AtomicRefCell;
use log::warn;
+use malloc_size_of_derive::MallocSizeOf;
use parking_lot::RwLock;
use style::stylesheets::DocumentStyleSheet;
use style::values::computed::{FontStyle, FontWeight};
@@ -15,7 +15,7 @@ use crate::font::FontDescriptor;
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
use crate::system_font_service::{FontIdentifier, LowercaseFontFamilyName};
-#[derive(Default)]
+#[derive(Default, MallocSizeOf)]
pub struct FontStore {
pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
web_fonts_loading_for_stylesheets: Vec<(DocumentStyleSheet, usize)>,
@@ -134,7 +134,7 @@ impl FontStore {
///
/// This optimization is taken from:
/// <https://searchfox.org/mozilla-central/source/gfx/thebes/gfxFontEntry.cpp>.
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, MallocSizeOf)]
struct SimpleFamily {
regular: Option<FontTemplateRef>,
bold: Option<FontTemplateRef>,
@@ -190,7 +190,7 @@ impl SimpleFamily {
}
}
/// A list of font templates that make up a given font family.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, MallocSizeOf)]
pub struct FontTemplates {
pub(crate) templates: Vec<FontTemplateRef>,
simple_family: Option<SimpleFamily>,
@@ -263,7 +263,7 @@ impl FontTemplates {
}
}
- let new_template = Arc::new(AtomicRefCell::new(new_template));
+ let new_template = FontTemplateRef::new(new_template);
self.templates.push(new_template.clone());
self.update_simple_family(new_template);
}
diff --git a/components/fonts/font_template.rs b/components/fonts/font_template.rs
index eca1017d14e..b8173ee0317 100644
--- a/components/fonts/font_template.rs
+++ b/components/fonts/font_template.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::fmt::{Debug, Error, Formatter};
-use std::ops::RangeInclusive;
+use std::ops::{Deref, RangeInclusive};
use std::sync::Arc;
use atomic_refcell::AtomicRefCell;
@@ -20,7 +20,21 @@ use crate::system_font_service::{
};
/// A reference to a [`FontTemplate`] with shared ownership and mutability.
-pub type FontTemplateRef = Arc<AtomicRefCell<FontTemplate>>;
+#[derive(Clone, Debug, MallocSizeOf)]
+pub struct FontTemplateRef(#[conditional_malloc_size_of] Arc<AtomicRefCell<FontTemplate>>);
+
+impl FontTemplateRef {
+ pub fn new(template: FontTemplate) -> Self {
+ Self(Arc::new(AtomicRefCell::new(template)))
+ }
+}
+
+impl Deref for FontTemplateRef {
+ type Target = Arc<AtomicRefCell<FontTemplate>>;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
/// Describes how to select a font from a given family. This is very basic at the moment and needs
/// to be expanded or refactored when we support more of the font styling parameters.
diff --git a/components/fonts/system_font_service.rs b/components/fonts/system_font_service.rs
index 91b2d810eff..f799affa7c8 100644
--- a/components/fonts/system_font_service.rs
+++ b/components/fonts/system_font_service.rs
@@ -6,16 +6,19 @@ use std::borrow::ToOwned;
use std::cell::OnceCell;
use std::collections::HashMap;
use std::ops::{Deref, RangeInclusive};
-use std::sync::Arc;
use std::{fmt, thread};
use app_units::Au;
-use atomic_refcell::AtomicRefCell;
use compositing_traits::CrossProcessCompositorApi;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use log::debug;
+use malloc_size_of::MallocSizeOf as MallocSizeOfTrait;
use malloc_size_of_derive::MallocSizeOf;
use parking_lot::{Mutex, RwLock};
+use profile_traits::mem::{
+ ProcessReports, ProfilerChan, Report, ReportKind, ReportsChan, perform_memory_report,
+};
+use profile_traits::path;
use serde::{Deserialize, Serialize};
use servo_config::pref;
use servo_url::ServoUrl;
@@ -66,11 +69,12 @@ pub enum SystemFontServiceMessage {
),
GetFontKey(IpcSender<FontKey>),
GetFontInstanceKey(IpcSender<FontInstanceKey>),
+ CollectMemoryReport(ReportsChan),
Exit(IpcSender<()>),
Ping,
}
-#[derive(Default)]
+#[derive(Default, MallocSizeOf)]
struct ResolvedGenericFontFamilies {
default: OnceCell<LowercaseFontFamilyName>,
serif: OnceCell<LowercaseFontFamilyName>,
@@ -84,6 +88,7 @@ struct ResolvedGenericFontFamilies {
/// The system font service. There is one of these for every Servo instance. This is a thread,
/// responsible for reading the list of system fonts, handling requests to match against
/// them, and ensuring that only one copy of system font data is loaded at a time.
+#[derive(MallocSizeOf)]
pub struct SystemFontService {
port: IpcReceiver<SystemFontServiceMessage>,
local_families: FontStore,
@@ -118,8 +123,12 @@ impl SystemFontServiceProxySender {
}
impl SystemFontService {
- pub fn spawn(compositor_api: CrossProcessCompositorApi) -> SystemFontServiceProxySender {
+ pub fn spawn(
+ compositor_api: CrossProcessCompositorApi,
+ memory_profiler_sender: ProfilerChan,
+ ) -> SystemFontServiceProxySender {
let (sender, receiver) = ipc::channel().unwrap();
+ let memory_reporter_sender = sender.clone();
thread::Builder::new()
.name("SystemFontService".to_owned())
@@ -138,7 +147,13 @@ impl SystemFontService {
cache.fetch_new_keys();
cache.refresh_local_families();
- cache.run();
+
+ memory_profiler_sender.run_with_memory_reporting(
+ || cache.run(),
+ "system-fonts".to_owned(),
+ memory_reporter_sender,
+ SystemFontServiceMessage::CollectMemoryReport,
+ );
})
.expect("Thread spawning failed");
@@ -172,6 +187,9 @@ impl SystemFontService {
self.fetch_new_keys();
let _ = result_sender.send(self.free_font_instance_keys.pop().unwrap());
},
+ SystemFontServiceMessage::CollectMemoryReport(report_sender) => {
+ self.collect_memory_report(report_sender);
+ },
SystemFontServiceMessage::Ping => (),
SystemFontServiceMessage::Exit(result) => {
let _ = result.send(());
@@ -181,6 +199,17 @@ impl SystemFontService {
}
}
+ fn collect_memory_report(&self, report_sender: ReportsChan) {
+ perform_memory_report(|ops| {
+ let reports = vec![Report {
+ path: path!["system-fonts"],
+ kind: ReportKind::ExplicitSystemHeapSize,
+ size: self.size_of(ops),
+ }];
+ report_sender.send(ProcessReports::new(reports));
+ });
+ }
+
#[cfg_attr(
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
@@ -528,11 +557,7 @@ impl SystemFontServiceProxy {
panic!("SystemFontService has already exited.");
};
- let templates: Vec<_> = templates
- .into_iter()
- .map(AtomicRefCell::new)
- .map(Arc::new)
- .collect();
+ let templates: Vec<_> = templates.into_iter().map(FontTemplateRef::new).collect();
self.templates.write().insert(cache_key, templates.clone());
templates
diff --git a/components/fonts/tests/font.rs b/components/fonts/tests/font.rs
index 78c507e7b93..a473be9222b 100644
--- a/components/fonts/tests/font.rs
+++ b/components/fonts/tests/font.rs
@@ -5,14 +5,13 @@
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
-use std::sync::Arc;
use app_units::Au;
use euclid::num::Zero;
use fonts::platform::font::PlatformFont;
use fonts::{
- Font, FontData, FontDescriptor, FontIdentifier, FontTemplate, PlatformFontMethods,
- ShapingFlags, ShapingOptions,
+ Font, FontData, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef,
+ PlatformFontMethods, ShapingFlags, ShapingOptions,
};
use servo_url::ServoUrl;
use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
@@ -42,13 +41,7 @@ fn make_font(path: PathBuf) -> Font {
variant: FontVariantCaps::Normal,
pt_size: Au::from_px(24),
};
- Font::new(
- Arc::new(atomic_refcell::AtomicRefCell::new(template)),
- descriptor,
- Some(data),
- None,
- )
- .unwrap()
+ Font::new(FontTemplateRef::new(template), descriptor, Some(data), None).unwrap()
}
#[test]
diff --git a/components/fonts/tests/font_context.rs b/components/fonts/tests/font_context.rs
index aeafa02bcc1..0793c1e4ce1 100644
--- a/components/fonts/tests/font_context.rs
+++ b/components/fonts/tests/font_context.rs
@@ -137,6 +137,7 @@ mod font_context {
break;
},
SystemFontServiceMessage::Ping => {},
+ SystemFontServiceMessage::CollectMemoryReport(..) => {},
}
}
}
diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs
index 8799dd2da0c..186272cda36 100644
--- a/components/layout/display_list/mod.rs
+++ b/components/layout/display_list/mod.rs
@@ -1020,7 +1020,7 @@ impl<'a> BuilderForBoxFragment<'a> {
for extra_background in extra_backgrounds {
let positioning_area = extra_background.rect;
let painter = BackgroundPainter {
- style: &extra_background.style,
+ style: &extra_background.style.borrow_mut().0,
painting_area_override: None,
positioning_area_override: Some(
positioning_area
diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs
index 65ad1c4aa93..4cd8f278498 100644
--- a/components/layout/fragment_tree/box_fragment.rs
+++ b/components/layout/fragment_tree/box_fragment.rs
@@ -17,6 +17,7 @@ use style::properties::ComputedValues;
use style::values::specified::box_::DisplayOutside;
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment};
+use crate::ArcRefCell;
use crate::display_list::ToWebRender;
use crate::formatting_contexts::Baselines;
use crate::geom::{
@@ -40,10 +41,14 @@ pub(crate) enum BackgroundMode {
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 {
- #[conditional_malloc_size_of]
- pub style: ServoArc<ComputedValues>,
+ pub style: SharedBackgroundStyle,
pub rect: PhysicalRect<Au>,
}
diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs
index b8d91c38027..cdf76d3fed0 100644
--- a/components/layout/layout_impl.rs
+++ b/components/layout/layout_impl.rs
@@ -4,9 +4,8 @@
#![allow(unsafe_code)]
-use std::cell::{Cell, LazyCell, RefCell};
-use std::collections::{HashMap, HashSet};
-use std::ffi::c_void;
+use std::cell::{Cell, RefCell};
+use std::collections::HashMap;
use std::fmt::Debug;
use std::process;
use std::sync::{Arc, LazyLock};
@@ -95,10 +94,6 @@ use crate::{BoxTree, FragmentTree};
static STYLE_THREAD_POOL: Mutex<&style::global_style_data::STYLE_THREAD_POOL> =
Mutex::new(&style::global_style_data::STYLE_THREAD_POOL);
-thread_local!(static SEEN_POINTERS: LazyCell<RefCell<HashSet<*const c_void>>> = const {
- LazyCell::new(|| RefCell::new(HashSet::new()))
-});
-
/// A CSS file to style the user agent stylesheet.
static USER_AGENT_CSS: &[u8] = include_bytes!("./stylesheets/user-agent.css");
diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs
index 8370e9aeb89..133904db7ae 100644
--- a/components/layout/table/construct.rs
+++ b/components/layout/table/construct.rs
@@ -29,7 +29,7 @@ use crate::formatting_contexts::{
IndependentFormattingContext, IndependentFormattingContextContents,
IndependentNonReplacedContents,
};
-use crate::fragment_tree::BaseFragmentInfo;
+use crate::fragment_tree::{BackgroundStyle, BaseFragmentInfo, SharedBackgroundStyle};
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
@@ -722,9 +722,10 @@ impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
let style = anonymous_info.style.clone();
self.push_table_row(ArcRefCell::new(TableTrack {
- base: LayoutBoxBase::new((&anonymous_info).into(), style),
+ 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)),
}));
}
@@ -766,6 +767,9 @@ 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(),
+ )),
});
self.builder.table.row_groups.push(row_group.clone());
@@ -808,6 +812,9 @@ 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(),
+ )),
});
self.push_table_row(row.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
@@ -853,6 +860,9 @@ 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(),
+ )),
});
self.builder.table.column_groups.push(column_group.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
@@ -1135,6 +1145,9 @@ 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(),
+ )),
});
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 2efe339837e..00dac210625 100644
--- a/components/layout/table/layout.rs
+++ b/components/layout/table/layout.rs
@@ -2063,7 +2063,7 @@ impl<'a> TableLayout<'a> {
let column_group = column_group.borrow();
let rect = make_relative_to_row_start(dimensions.get_column_group_rect(&column_group));
fragment.add_extra_background(ExtraBackground {
- style: column_group.base.style.clone(),
+ style: column_group.shared_background_style.clone(),
rect,
})
}
@@ -2072,7 +2072,7 @@ impl<'a> TableLayout<'a> {
if !column.is_anonymous {
let rect = make_relative_to_row_start(dimensions.get_column_rect(column_index));
fragment.add_extra_background(ExtraBackground {
- style: column.base.style.clone(),
+ style: column.shared_background_style.clone(),
rect,
})
}
@@ -2085,7 +2085,7 @@ impl<'a> TableLayout<'a> {
let rect =
make_relative_to_row_start(dimensions.get_row_group_rect(&row_group.borrow()));
fragment.add_extra_background(ExtraBackground {
- style: row_group.borrow().base.style.clone(),
+ style: row_group.borrow().shared_background_style.clone(),
rect,
})
}
@@ -2093,7 +2093,7 @@ impl<'a> TableLayout<'a> {
let row = row.borrow();
let rect = make_relative_to_row_start(row_fragment_layout.rect);
fragment.add_extra_background(ExtraBackground {
- style: row.base.style.clone(),
+ style: row.shared_background_style.clone(),
rect,
})
}
diff --git a/components/layout/table/mod.rs b/components/layout/table/mod.rs
index fe7f90437b8..8e2783e2919 100644
--- a/components/layout/table/mod.rs
+++ b/components/layout/table/mod.rs
@@ -85,7 +85,7 @@ use super::flow::BlockFormattingContext;
use crate::cell::ArcRefCell;
use crate::flow::BlockContainer;
use crate::formatting_contexts::IndependentFormattingContext;
-use crate::fragment_tree::{BaseFragmentInfo, Fragment};
+use crate::fragment_tree::{BaseFragmentInfo, Fragment, SharedBackgroundStyle};
use crate::geom::PhysicalVec;
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::BorderStyleColor;
@@ -288,6 +288,11 @@ pub struct TableTrack {
/// Whether or not this [`TableTrack`] was anonymous, for instance created due to
/// a `span` attribute set on a parent `<colgroup>`.
is_anonymous: bool,
+
+ /// 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,
}
#[derive(Debug, MallocSizeOf, PartialEq)]
@@ -308,6 +313,11 @@ pub struct TableTrackGroup {
/// The range of tracks in this [`TableTrackGroup`].
track_range: Range<usize>,
+
+ /// 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,
}
impl TableTrackGroup {
diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs
index accd0aaf243..2bdeedf986d 100644
--- a/components/malloc_size_of/lib.rs
+++ b/components/malloc_size_of/lib.rs
@@ -50,6 +50,7 @@ use std::cell::OnceCell;
use std::collections::BinaryHeap;
use std::hash::{BuildHasher, Hash};
use std::ops::Range;
+use std::rc::Rc;
use std::sync::Arc;
use style::values::generics::length::GenericLengthPercentageOrAuto;
@@ -577,6 +578,28 @@ impl<T: MallocSizeOf> MallocConditionalSizeOf for Arc<T> {
}
}
+impl<T> MallocUnconditionalShallowSizeOf for Rc<T> {
+ fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ unsafe { ops.malloc_size_of(Rc::as_ptr(self)) }
+ }
+}
+
+impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Rc<T> {
+ fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
+ }
+}
+
+impl<T: MallocSizeOf> MallocConditionalSizeOf for Rc<T> {
+ fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ if ops.have_seen_ptr(Rc::as_ptr(self)) {
+ 0
+ } else {
+ self.unconditional_size_of(ops)
+ }
+ }
+}
+
/// If a mutex is stored directly as a member of a data type that is being measured,
/// it is the unique owner of its contents and deserves to be measured.
///
@@ -709,6 +732,12 @@ impl<T> MallocSizeOf for ipc_channel::ipc::IpcSender<T> {
}
}
+impl<T> MallocSizeOf for ipc_channel::ipc::IpcReceiver<T> {
+ fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
+ 0
+ }
+}
+
impl MallocSizeOf for ipc_channel::ipc::IpcSharedMemory {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
self.len()
@@ -749,7 +778,10 @@ malloc_size_of_is_0!(std::time::SystemTime);
malloc_size_of_is_0!(style::data::ElementData);
malloc_size_of_is_0!(style::font_face::SourceList);
malloc_size_of_is_0!(style::properties::ComputedValues);
+malloc_size_of_is_0!(style::properties::declaration_block::PropertyDeclarationBlock);
malloc_size_of_is_0!(style::queries::values::PrefersColorScheme);
+malloc_size_of_is_0!(style::stylesheets::Stylesheet);
+malloc_size_of_is_0!(style::values::specified::source_size_list::SourceSizeList);
malloc_size_of_is_0!(taffy::Layout);
malloc_size_of_is_0!(unicode_bidi::Level);
malloc_size_of_is_0!(unicode_script::Script);
@@ -773,6 +805,7 @@ malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BorderStyle);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BoxShadowClipMode);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ColorF);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ExtendMode);
+malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontKey);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontInstanceKey);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GlyphInstance);
malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GradientStop);
@@ -817,6 +850,14 @@ where
}
}
+impl<T> MallocSizeOf for style::shared_lock::Locked<T> {
+ fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
+ // TODO: fix this implementation when Locked derives MallocSizeOf.
+ 0
+ //<style::shared_lock::Locked<T> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
+ }
+}
+
impl<T: MallocSizeOf> MallocSizeOf for atomic_refcell::AtomicRefCell<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.borrow().size_of(ops)
diff --git a/components/pixels/lib.rs b/components/pixels/lib.rs
index 24386ff830a..c1f57875c6d 100644
--- a/components/pixels/lib.rs
+++ b/components/pixels/lib.rs
@@ -294,9 +294,10 @@ pub fn generic_transform_inplace<
match MULTIPLY {
1 => {
let a = rgba[3];
- multiply_u8_color(rgba[0], a);
- multiply_u8_color(rgba[1], a);
- multiply_u8_color(rgba[2], a);
+
+ rgba[0] = multiply_u8_color(rgba[0], a);
+ rgba[1] = multiply_u8_color(rgba[1], a);
+ rgba[2] = multiply_u8_color(rgba[2], a);
},
2 => {
let a = rgba[3] as u32;
diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs
index 6c987270911..7e7e752bc0c 100644
--- a/components/script/dom/bindings/cell.rs
+++ b/components/script/dom/bindings/cell.rs
@@ -10,6 +10,7 @@ pub(crate) use std::cell::{Ref, RefCell, RefMut};
#[cfg(feature = "refcell_backtrace")]
pub(crate) use accountable_refcell::{Ref, RefCell, RefMut, ref_filter_map};
+use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOfOps};
#[cfg(not(feature = "refcell_backtrace"))]
pub(crate) use ref_filter_map::ref_filter_map;
@@ -24,6 +25,12 @@ pub(crate) struct DomRefCell<T> {
value: RefCell<T>,
}
+impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for DomRefCell<T> {
+ fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ self.value.borrow().conditional_size_of(ops)
+ }
+}
+
// Functionality specific to Servo's `DomRefCell` type
// ===================================================
diff --git a/components/script/dom/clipboard.rs b/components/script/dom/clipboard.rs
index 94c8b3c0f19..25878a1b29b 100644
--- a/components/script/dom/clipboard.rs
+++ b/components/script/dom/clipboard.rs
@@ -3,24 +3,75 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::rc::Rc;
+use std::str::FromStr;
use constellation_traits::BlobImpl;
+use data_url::mime::Mime;
use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
+use js::rust::HandleValue as SafeHandleValue;
use crate::dom::bindings::codegen::Bindings::ClipboardBinding::{
ClipboardMethods, PresentationStyle,
};
+use crate::dom::bindings::error::Error;
use crate::dom::bindings::refcounted::TrustedPromise;
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::blob::Blob;
+use crate::dom::clipboarditem::Representation;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
+use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
use crate::dom::window::Window;
-use crate::script_runtime::CanGc;
+use crate::realms::{InRealm, enter_realm};
+use crate::routed_promise::{RoutedPromiseListener, route_promise};
+use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
+
+/// The fulfillment handler for the reacting to representationDataPromise part of
+/// <https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext>.
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+struct RepresentationDataPromiseFulfillmentHandler {
+ #[ignore_malloc_size_of = "Rc are hard"]
+ promise: Rc<Promise>,
+}
+
+impl Callback for RepresentationDataPromiseFulfillmentHandler {
+ /// The fulfillment case of Step 3.4.1.1.4.3 of
+ /// <https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext>.
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // If v is a DOMString, then follow the below steps:
+ // Resolve p with v.
+ // Return p.
+ self.promise.resolve(cx, v, can_gc);
+
+ // NOTE: Since we ask text from arboard, v can't be a Blob
+ // If v is a Blob, then follow the below steps:
+ // Let string be the result of UTF-8 decoding v’s underlying byte sequence.
+ // Resolve p with string.
+ // Return p.
+ }
+}
+
+/// The rejection handler for the reacting to representationDataPromise part of
+/// <https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext>.
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+struct RepresentationDataPromiseRejectionHandler {
+ #[ignore_malloc_size_of = "Rc are hard"]
+ promise: Rc<Promise>,
+}
+
+impl Callback for RepresentationDataPromiseRejectionHandler {
+ /// The rejection case of Step 3.4.1.1.4.3 of
+ /// <https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext>.
+ fn callback(&self, _cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Reject p with "NotFoundError" DOMException in realm.
+ // Return p.
+ self.promise.reject_error(Error::NotFound, can_gc);
+ }
+}
#[dom_struct]
pub(crate) struct Clipboard {
@@ -40,6 +91,34 @@ impl Clipboard {
}
impl ClipboardMethods<crate::DomTypeHolder> for Clipboard {
+ /// <https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext>
+ fn ReadText(&self, can_gc: CanGc) -> Rc<Promise> {
+ // Step 1 Let realm be this's relevant realm.
+ let global = self.global();
+
+ // Step 2 Let p be a new promise in realm.
+ let p = Promise::new(&global, can_gc);
+
+ // Step 3 Run the following steps in parallel:
+
+ // TODO Step 3.1 Let r be the result of running check clipboard read permission.
+ // Step 3.2 If r is false, then:
+ // Step 3.2.1 Queue a global task on the permission task source, given realm’s global object,
+ // to reject p with "NotAllowedError" DOMException in realm.
+ // Step 3.2.2 Abort these steps.
+
+ // Step 3.3 Let data be a copy of the system clipboard data.
+ let window = global.as_window();
+ let sender = route_promise(&p, self, global.task_manager().clipboard_task_source());
+ window.send_to_embedder(EmbedderMsg::GetClipboardText(window.webview_id(), sender));
+
+ // Step 3.4 Queue a global task on the clipboard task source,
+ // given realm’s global object, to perform the below steps:
+ // NOTE: We queue the task inside route_promise and perform the steps inside handle_response
+
+ p
+ }
+
/// <https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext>
fn WriteText(&self, data: DOMString, can_gc: CanGc) -> Rc<Promise> {
// Step 1 Let realm be this's relevant realm.
@@ -95,6 +174,71 @@ impl ClipboardMethods<crate::DomTypeHolder> for Clipboard {
}
}
+impl RoutedPromiseListener<Result<String, String>> for Clipboard {
+ fn handle_response(
+ &self,
+ response: Result<String, String>,
+ promise: &Rc<Promise>,
+ can_gc: CanGc,
+ ) {
+ let global = self.global();
+ let text = response.unwrap_or_default();
+
+ // Step 3.4.1 For each systemClipboardItem in data:
+ // Step 3.4.1.1 For each systemClipboardRepresentation in systemClipboardItem:
+ // TODO: Arboard provide the first item that has a String representation
+
+ // Step 3.4.1.1.1 Let mimeType be the result of running the
+ // well-known mime type from os specific format algorithm given systemClipboardRepresentation’s name.
+ // Note: This is done by arboard, so we just convert the format to a MIME
+ let mime_type = Mime::from_str("text/plain").unwrap();
+
+ // Step 3.4.1.1.2 If mimeType is null, continue this loop.
+ // Note: Since the previous step is infallible, we don't need to handle this case
+
+ // Step 3.4.1.1.3 Let representation be a new representation.
+ let representation = Representation {
+ mime_type,
+ is_custom: false,
+ data: Promise::new_resolved(
+ &global,
+ GlobalScope::get_cx(),
+ DOMString::from(text),
+ can_gc,
+ ),
+ };
+
+ // Step 3.4.1.1.4 If representation’s MIME type essence is "text/plain", then:
+
+ // Step 3.4.1.1.4.1 Set representation’s MIME type to mimeType.
+ // Note: Done when creating a new representation
+
+ // Step 3.4.1.1.4.2 Let representationDataPromise be the representation’s data.
+ // Step 3.4.1.1.4.3 React to representationDataPromise:
+ let fulfillment_handler = Box::new(RepresentationDataPromiseFulfillmentHandler {
+ promise: promise.clone(),
+ });
+ let rejection_handler = Box::new(RepresentationDataPromiseRejectionHandler {
+ promise: promise.clone(),
+ });
+ let handler = PromiseNativeHandler::new(
+ &global,
+ Some(fulfillment_handler),
+ Some(rejection_handler),
+ can_gc,
+ );
+ let realm = enter_realm(&*global);
+ let comp = InRealm::Entered(&realm);
+ representation
+ .data
+ .append_native_handler(&handler, comp, can_gc);
+
+ // Step 3.4.2 Reject p with "NotFoundError" DOMException in realm.
+ // Step 3.4.3 Return p.
+ // NOTE: We follow the same behaviour of Gecko by doing nothing if no text is available instead of rejecting p
+ }
+}
+
/// <https://w3c.github.io/clipboard-apis/#write-blobs-and-option-to-the-clipboard>
fn write_blobs_and_option_to_the_clipboard(
window: &Window,
diff --git a/components/script/dom/clipboarditem.rs b/components/script/dom/clipboarditem.rs
index c1c66a403b3..129beb686c1 100644
--- a/components/script/dom/clipboarditem.rs
+++ b/components/script/dom/clipboarditem.rs
@@ -29,13 +29,13 @@ const CUSTOM_FORMAT_PREFIX: &str = "web ";
/// <https://w3c.github.io/clipboard-apis/#representation>
#[derive(JSTraceable, MallocSizeOf)]
-struct Representation {
+pub(super) struct Representation {
#[no_trace]
#[ignore_malloc_size_of = "Extern type"]
- mime_type: Mime,
- is_custom: bool,
+ pub mime_type: Mime,
+ pub is_custom: bool,
#[ignore_malloc_size_of = "Rc is hard"]
- data: Rc<Promise>,
+ pub data: Rc<Promise>,
}
#[dom_struct]
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index ae48fa1fb2f..a4b05e7f445 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -4307,21 +4307,21 @@ impl Document {
type_: csp::InlineCheckType,
source: &str,
) -> csp::CheckResult {
- let element = csp::Element {
- nonce: el
- .get_attribute(&ns!(), &local_name!("nonce"))
- .map(|attr| Cow::Owned(attr.value().to_string())),
- };
let (result, violations) = match self.get_csp_list() {
None => {
return csp::CheckResult::Allowed;
},
Some(csp_list) => {
+ let element = csp::Element {
+ nonce: el
+ .get_attribute(&ns!(), &local_name!("nonce"))
+ .map(|attr| Cow::Owned(attr.value().to_string())),
+ };
csp_list.should_elements_inline_type_behavior_be_blocked(&element, type_, source)
},
};
- self.global().report_csp_violations(violations);
+ self.global().report_csp_violations(violations, Some(el));
result
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index b2168846fad..7f38e55fb14 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -179,7 +179,7 @@ pub struct Element {
/// <https://dom.spec.whatwg.org/#concept-element-is-value>
#[no_trace]
is: DomRefCell<Option<LocalName>>,
- #[ignore_malloc_size_of = "Arc"]
+ #[conditional_malloc_size_of]
#[no_trace]
style_attribute: DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
attr_list: MutNullableDom<NamedNodeMap>,
diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs
index e199e12f655..743ced42a4b 100644
--- a/components/script/dom/event.rs
+++ b/components/script/dom/event.rs
@@ -1040,14 +1040,39 @@ impl From<bool> for EventCancelable {
}
impl From<EventCancelable> for bool {
- fn from(bubbles: EventCancelable) -> Self {
- match bubbles {
+ fn from(cancelable: EventCancelable) -> Self {
+ match cancelable {
EventCancelable::Cancelable => true,
EventCancelable::NotCancelable => false,
}
}
}
+#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
+pub(crate) enum EventComposed {
+ Composed,
+ NotComposed,
+}
+
+impl From<bool> for EventComposed {
+ fn from(boolean: bool) -> Self {
+ if boolean {
+ EventComposed::Composed
+ } else {
+ EventComposed::NotComposed
+ }
+ }
+}
+
+impl From<EventComposed> for bool {
+ fn from(composed: EventComposed) -> Self {
+ match composed {
+ EventComposed::Composed => true,
+ EventComposed::NotComposed => false,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, Eq, JSTraceable, PartialEq)]
#[repr(u16)]
#[derive(MallocSizeOf)]
diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs
index 273abda0a02..7cf7bd6106f 100644
--- a/components/script/dom/eventsource.rs
+++ b/components/script/dom/eventsource.rs
@@ -448,7 +448,7 @@ impl FetchResponseListener for EventSourceContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 98c4c3ed53d..902d4622db9 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -106,6 +106,7 @@ use crate::dom::crypto::Crypto;
use crate::dom::dedicatedworkerglobalscope::{
DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
};
+use crate::dom::element::Element;
use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventsource::EventSource;
@@ -115,6 +116,7 @@ use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::messageevent::MessageEvent;
use crate::dom::messageport::MessagePort;
+use crate::dom::node::Node;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::performance::Performance;
use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
@@ -2930,7 +2932,7 @@ impl GlobalScope {
let (is_js_evaluation_allowed, violations) = csp_list.is_js_evaluation_allowed(source);
- self.report_csp_violations(violations);
+ self.report_csp_violations(violations, None);
is_js_evaluation_allowed == CheckResult::Allowed
}
@@ -2957,7 +2959,7 @@ impl GlobalScope {
let (result, violations) =
csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
- self.report_csp_violations(violations);
+ self.report_csp_violations(violations, None);
result == CheckResult::Blocked
}
@@ -3444,8 +3446,13 @@ impl GlobalScope {
unreachable!();
}
+ /// <https://www.w3.org/TR/CSP/#report-violation>
#[allow(unsafe_code)]
- pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
+ pub(crate) fn report_csp_violations(
+ &self,
+ violations: Vec<Violation>,
+ element: Option<&Element>,
+ ) {
let scripted_caller =
unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
for violation in violations {
@@ -3471,7 +3478,38 @@ impl GlobalScope {
.line_number(scripted_caller.line)
.column_number(scripted_caller.col + 1)
.build(self);
- let task = CSPViolationReportTask::new(self, report);
+ // Step 1: Let global be violation’s global object.
+ // We use `self` as `global`;
+ // Step 2: Let target be violation’s element.
+ let target = element.and_then(|event_target| {
+ // Step 3.1: If target is not null, and global is a Window,
+ // and target’s shadow-including root is not global’s associated Document, set target to null.
+ if let Some(window) = self.downcast::<Window>() {
+ if !window
+ .Document()
+ .upcast::<Node>()
+ .is_shadow_including_inclusive_ancestor_of(event_target.upcast())
+ {
+ return None;
+ }
+ }
+ Some(event_target)
+ });
+ let target = match target {
+ // Step 3.2: If target is null:
+ None => {
+ // Step 3.2.2: If target is a Window, set target to target’s associated Document.
+ if let Some(window) = self.downcast::<Window>() {
+ Trusted::new(window.Document().upcast())
+ } else {
+ // Step 3.2.1: Set target to violation’s global object.
+ Trusted::new(self.upcast())
+ }
+ },
+ Some(event_target) => Trusted::new(event_target.upcast()),
+ };
+ // Step 3: Queue a task to run the following steps:
+ let task = CSPViolationReportTask::new(Trusted::new(self), target, report);
self.task_manager()
.dom_manipulation_task_source()
.queue(task);
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index adff445ae1c..a79c7f6e463 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -97,6 +97,7 @@ enum ParseState {
AfterDescriptor,
}
+#[derive(MallocSizeOf)]
pub(crate) struct SourceSet {
image_sources: Vec<ImageSource>,
source_size: SourceSizeList,
@@ -111,13 +112,13 @@ impl SourceSet {
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub struct ImageSource {
pub url: String,
pub descriptor: Descriptor,
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub struct Descriptor {
pub width: Option<u32>,
pub density: Option<f64>,
@@ -145,7 +146,7 @@ struct ImageRequest {
parsed_url: Option<ServoUrl>,
source_url: Option<USVString>,
blocker: DomRefCell<Option<LoadBlocker>>,
- #[ignore_malloc_size_of = "Arc"]
+ #[conditional_malloc_size_of]
#[no_trace]
image: Option<Arc<Image>>,
#[no_trace]
@@ -162,7 +163,6 @@ pub(crate) struct HTMLImageElement {
pending_request: DomRefCell<ImageRequest>,
form_owner: MutNullableDom<HTMLFormElement>,
generation: Cell<u32>,
- #[ignore_malloc_size_of = "SourceSet"]
source_set: DomRefCell<SourceSet>,
last_selected_source: DomRefCell<Option<USVString>>,
#[ignore_malloc_size_of = "promises are hard"]
@@ -298,7 +298,7 @@ impl FetchResponseListener for ImageContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs
index db5c14af450..18bd426acdb 100644
--- a/components/script/dom/htmllinkelement.rs
+++ b/components/script/dom/htmllinkelement.rs
@@ -98,7 +98,7 @@ pub(crate) struct HTMLLinkElement {
#[no_trace]
relations: Cell<LinkRelations>,
- #[ignore_malloc_size_of = "Arc"]
+ #[conditional_malloc_size_of]
#[no_trace]
stylesheet: DomRefCell<Option<Arc<Stylesheet>>>,
cssom_stylesheet: MutNullableDom<CSSStyleSheet>,
@@ -773,7 +773,7 @@ impl FetchResponseListener for PrefetchContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 361c22c1250..391da272ef3 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -2951,7 +2951,7 @@ impl FetchResponseListener for HTMLMediaElementFetchListener {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 9d0ca807748..4ee1397b4ed 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -281,19 +281,18 @@ pub(crate) enum ScriptType {
pub(crate) struct CompiledSourceCode {
#[ignore_malloc_size_of = "SM handles JS values"]
pub(crate) source_code: Stencil,
- #[ignore_malloc_size_of = "Rc is hard"]
+ #[conditional_malloc_size_of = "Rc is hard"]
pub(crate) original_text: Rc<DOMString>,
}
-#[derive(JSTraceable)]
+#[derive(JSTraceable, MallocSizeOf)]
pub(crate) enum SourceCode {
- Text(Rc<DOMString>),
+ Text(#[conditional_malloc_size_of] Rc<DOMString>),
Compiled(CompiledSourceCode),
}
#[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct ScriptOrigin {
- #[ignore_malloc_size_of = "Rc is hard"]
code: SourceCode,
#[no_trace]
url: ServoUrl,
@@ -547,7 +546,8 @@ impl FetchResponseListener for ClassicContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ let elem = self.elem.root();
+ global.report_csp_violations(violations, Some(elem.upcast::<Element>()));
}
}
diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs
index 0deb507f283..aed08b7bcf6 100644
--- a/components/script/dom/htmlstyleelement.rs
+++ b/components/script/dom/htmlstyleelement.rs
@@ -4,6 +4,7 @@
use std::cell::Cell;
+use content_security_policy as csp;
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use js::rust::HandleObject;
@@ -33,7 +34,7 @@ use crate::stylesheet_loader::{StylesheetLoader, StylesheetOwner};
#[dom_struct]
pub(crate) struct HTMLStyleElement {
htmlelement: HTMLElement,
- #[ignore_malloc_size_of = "Arc"]
+ #[conditional_malloc_size_of]
#[no_trace]
stylesheet: DomRefCell<Option<Arc<Stylesheet>>>,
cssom_stylesheet: MutNullableDom<CSSStyleSheet>,
@@ -97,8 +98,21 @@ impl HTMLStyleElement {
return;
}
- let window = node.owner_window();
let doc = self.owner_document();
+
+ // Step 5: If the Should element's inline behavior be blocked by Content Security Policy? algorithm
+ // returns "Blocked" when executed upon the style element, "style",
+ // and the style element's child text content, then return. [CSP]
+ if doc.should_elements_inline_type_behavior_be_blocked(
+ self.upcast(),
+ csp::InlineCheckType::Style,
+ &node.child_text_content(),
+ ) == csp::CheckResult::Blocked
+ {
+ return;
+ }
+
+ let window = node.owner_window();
let data = node
.GetTextContent()
.expect("Element.textContent must be a string");
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index 6f27c164d02..c5d21c19d9b 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -422,7 +422,7 @@ impl FetchResponseListener for PosterFrameFetchContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 4bc272db8dd..1622cf57b79 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -631,6 +631,8 @@ pub(crate) mod webgpu;
pub(crate) use self::webgpu::*;
#[cfg(not(feature = "webgpu"))]
pub(crate) mod gpucanvascontext;
+pub(crate) mod transformstream;
+pub(crate) mod transformstreamdefaultcontroller;
pub(crate) mod wheelevent;
#[allow(dead_code)]
pub(crate) mod window;
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index e9d36a01426..ca785773b48 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -3110,11 +3110,15 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
/// <https://dom.spec.whatwg.org/#dom-node-childnodes>
fn ChildNodes(&self, can_gc: CanGc) -> DomRoot<NodeList> {
- self.ensure_rare_data().child_list.or_init(|| {
- let doc = self.owner_doc();
- let window = doc.window();
- NodeList::new_child_list(window, self, can_gc)
- })
+ if let Some(list) = self.ensure_rare_data().child_list.get() {
+ return list;
+ }
+
+ let doc = self.owner_doc();
+ let window = doc.window();
+ let list = NodeList::new_child_list(window, self, can_gc);
+ self.ensure_rare_data().child_list.set(Some(&list));
+ list
}
/// <https://dom.spec.whatwg.org/#dom-node-firstchild>
diff --git a/components/script/dom/notification.rs b/components/script/dom/notification.rs
index 4dbb97430e5..1aecb785475 100644
--- a/components/script/dom/notification.rs
+++ b/components/script/dom/notification.rs
@@ -795,7 +795,7 @@ impl FetchResponseListener for ResourceFetchListener {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/readablestreamdefaultcontroller.rs b/components/script/dom/readablestreamdefaultcontroller.rs
index c52fb712a03..80c800d1bbe 100644
--- a/components/script/dom/readablestreamdefaultcontroller.rs
+++ b/components/script/dom/readablestreamdefaultcontroller.rs
@@ -383,7 +383,6 @@ impl ReadableStreamDefaultController {
}
/// <https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller>
- #[allow(unsafe_code)]
pub(crate) fn setup(
&self,
stream: DomRoot<ReadableStream>,
@@ -866,7 +865,6 @@ impl ReadableStreamDefaultController {
}
/// <https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure>
- #[allow(unused)]
pub(crate) fn has_backpressure(&self) -> bool {
// If ! ReadableStreamDefaultControllerShouldCallPull(controller) is true, return false.
// Otherwise, return true.
diff --git a/components/script/dom/readablestreamgenericreader.rs b/components/script/dom/readablestreamgenericreader.rs
index 8ba1149bcb5..d2a109ee692 100644
--- a/components/script/dom/readablestreamgenericreader.rs
+++ b/components/script/dom/readablestreamgenericreader.rs
@@ -80,7 +80,6 @@ pub(crate) trait ReadableStreamGenericReader {
}
/// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-release>
- #[allow(unsafe_code)]
fn generic_release(&self, can_gc: CanGc) -> Fallible<()> {
// Let stream be reader.[[stream]].
diff --git a/components/script/dom/securitypolicyviolationevent.rs b/components/script/dom/securitypolicyviolationevent.rs
index 3580e525e55..3c528cc5814 100644
--- a/components/script/dom/securitypolicyviolationevent.rs
+++ b/components/script/dom/securitypolicyviolationevent.rs
@@ -15,7 +15,7 @@ use crate::dom::bindings::codegen::Bindings::SecurityPolicyViolationEventBinding
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
-use crate::dom::event::{Event, EventBubbles, EventCancelable};
+use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
@@ -70,12 +70,14 @@ impl SecurityPolicyViolationEvent {
)
}
+ #[allow(clippy::too_many_arguments)]
fn new_with_proto(
global: &GlobalScope,
proto: Option<HandleObject>,
type_: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable,
+ composed: EventComposed,
init: &SecurityPolicyViolationEventInit,
can_gc: CanGc,
) -> DomRoot<Self> {
@@ -83,6 +85,7 @@ impl SecurityPolicyViolationEvent {
{
let event = ev.upcast::<Event>();
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
+ event.set_composed(bool::from(composed));
}
ev
}
@@ -92,10 +95,13 @@ impl SecurityPolicyViolationEvent {
type_: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable,
+ composed: EventComposed,
init: &SecurityPolicyViolationEventInit,
can_gc: CanGc,
) -> DomRoot<Self> {
- Self::new_with_proto(global, None, type_, bubbles, cancelable, init, can_gc)
+ Self::new_with_proto(
+ global, None, type_, bubbles, cancelable, composed, init, can_gc,
+ )
}
}
@@ -115,6 +121,7 @@ impl SecurityPolicyViolationEventMethods<crate::DomTypeHolder> for SecurityPolic
Atom::from(type_),
EventBubbles::from(init.parent.bubbles),
EventCancelable::from(init.parent.cancelable),
+ EventComposed::from(init.parent.composed),
init,
can_gc,
)
diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs
index 7fd0429612a..9dfbeda4030 100644
--- a/components/script/dom/servoparser/html.rs
+++ b/components/script/dom/servoparser/html.rs
@@ -16,6 +16,7 @@ use html5ever::{QualName, local_name, ns};
use markup5ever::TokenizerResult;
use script_bindings::trace::CustomTraceable;
use servo_url::ServoUrl;
+use style::attr::AttrValue;
use style::context::QuirksMode as StyleContextQuirksMode;
use xml5ever::LocalName;
@@ -116,18 +117,34 @@ impl Tokenizer {
}
}
-fn start_element<S: Serializer>(node: &Element, serializer: &mut S) -> io::Result<()> {
- let name = QualName::new(None, node.namespace().clone(), node.local_name().clone());
- let attrs = node
- .attrs()
- .iter()
- .map(|attr| {
- let qname = QualName::new(None, attr.namespace().clone(), attr.local_name().clone());
- let value = attr.value().clone();
- (qname, value)
- })
- .collect::<Vec<_>>();
- let attr_refs = attrs.iter().map(|(qname, value)| {
+/// <https://html.spec.whatwg.org/multipage/#html-fragment-serialisation-algorithm>
+fn start_element<S: Serializer>(element: &Element, serializer: &mut S) -> io::Result<()> {
+ let name = QualName::new(
+ None,
+ element.namespace().clone(),
+ element.local_name().clone(),
+ );
+
+ let mut attributes = vec![];
+
+ // The "is" value of an element is treated as if it was an attribute and it is serialized before all
+ // other attributes. If the element already has an "is" attribute then the "is" value is ignored.
+ if !element.has_attribute(&LocalName::from("is")) {
+ if let Some(is_value) = element.get_is() {
+ let qualified_name = QualName::new(None, ns!(), LocalName::from("is"));
+
+ attributes.push((qualified_name, AttrValue::String(is_value.to_string())));
+ }
+ }
+
+ // Collect all the "normal" attributes
+ attributes.extend(element.attrs().iter().map(|attr| {
+ let qname = QualName::new(None, attr.namespace().clone(), attr.local_name().clone());
+ let value = attr.value().clone();
+ (qname, value)
+ }));
+
+ let attr_refs = attributes.iter().map(|(qname, value)| {
let ar: AttrRef = (qname, &**value);
ar
});
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 3a1efdfb291..9e45124522a 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -1075,7 +1075,8 @@ impl FetchResponseListener for ParserContext {
};
let document = &parser.document;
let global = &document.global();
- global.report_csp_violations(violations);
+ // TODO(https://github.com/w3c/webappsec-csp/issues/687): Update after spec is resolved
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/dom/transformstream.rs b/components/script/dom/transformstream.rs
new file mode 100644
index 00000000000..023fe7ac483
--- /dev/null
+++ b/components/script/dom/transformstream.rs
@@ -0,0 +1,999 @@
+/* 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::cell::Cell;
+use std::ptr::{self};
+use std::rc::Rc;
+
+use dom_struct::dom_struct;
+use js::jsapi::{Heap, IsPromiseObject, JSObject};
+use js::jsval::{JSVal, ObjectValue, UndefinedValue};
+use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue, IntoHandle};
+use script_bindings::callback::ExceptionHandling;
+use script_bindings::realms::InRealm;
+
+use super::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategySize;
+use super::promisenativehandler::Callback;
+use super::types::{TransformStreamDefaultController, WritableStream};
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategy;
+use crate::dom::bindings::codegen::Bindings::TransformStreamBinding::TransformStreamMethods;
+use crate::dom::bindings::codegen::Bindings::TransformerBinding::Transformer;
+use crate::dom::bindings::conversions::ConversionResult;
+use crate::dom::bindings::error::{Error, Fallible};
+use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
+use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_algorithm};
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::promise::Promise;
+use crate::dom::readablestream::{ReadableStream, create_readable_stream};
+use crate::dom::types::PromiseNativeHandler;
+use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
+use crate::dom::writablestream::create_writable_stream;
+use crate::dom::writablestreamdefaultcontroller::UnderlyingSinkType;
+use crate::realms::enter_realm;
+use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
+
+impl js::gc::Rootable for TransformBackPressureChangePromiseFulfillment {}
+
+/// Reacting to backpressureChangePromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct TransformBackPressureChangePromiseFulfillment {
+ /// The result of reacting to backpressureChangePromise.
+ #[ignore_malloc_size_of = "Rc is hard"]
+ result_promise: Rc<Promise>,
+
+ #[ignore_malloc_size_of = "mozjs"]
+ chunk: Box<Heap<JSVal>>,
+
+ /// The writable used in the fulfillment steps
+ writable: Dom<WritableStream>,
+
+ controller: Dom<TransformStreamDefaultController>,
+}
+
+impl Callback for TransformBackPressureChangePromiseFulfillment {
+ /// Reacting to backpressureChangePromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Let writable be stream.[[writable]].
+ // Let state be writable.[[state]].
+ // If state is "erroring", throw writable.[[storedError]].
+ if self.writable.is_erroring() {
+ rooted!(in(*cx) let mut error = UndefinedValue());
+ self.writable.get_stored_error(error.handle_mut());
+ self.result_promise.reject(cx, error.handle(), can_gc);
+ return;
+ }
+
+ // Assert: state is "writable".
+ assert!(self.writable.is_writable());
+
+ // Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
+ rooted!(in(*cx) let mut chunk = UndefinedValue());
+ chunk.set(self.chunk.get());
+ let transform_result = self
+ .controller
+ .transform_stream_default_controller_perform_transform(
+ cx,
+ &self.writable.global(),
+ chunk.handle(),
+ can_gc,
+ )
+ .expect("perform transform failed");
+
+ // PerformTransformFulfillment and PerformTransformRejection do not need
+ // to be rooted because they only contain an Rc.
+ let handler = PromiseNativeHandler::new(
+ &self.writable.global(),
+ Some(Box::new(PerformTransformFulfillment {
+ result_promise: self.result_promise.clone(),
+ })),
+ Some(Box::new(PerformTransformRejection {
+ result_promise: self.result_promise.clone(),
+ })),
+ can_gc,
+ );
+
+ let realm = enter_realm(&*self.writable.global());
+ let comp = InRealm::Entered(&realm);
+ transform_result.append_native_handler(&handler, comp, can_gc);
+ }
+}
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+/// Reacting to fulfillment of performTransform as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm>
+struct PerformTransformFulfillment {
+ #[ignore_malloc_size_of = "Rc is hard"]
+ result_promise: Rc<Promise>,
+}
+
+impl Callback for PerformTransformFulfillment {
+ fn callback(&self, _cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Fulfilled: resolve the outer promise
+ self.result_promise.resolve_native(&(), can_gc);
+ }
+}
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+/// Reacting to rejection of performTransform as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm>
+struct PerformTransformRejection {
+ #[ignore_malloc_size_of = "Rc is hard"]
+ result_promise: Rc<Promise>,
+}
+
+impl Callback for PerformTransformRejection {
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Stream already errored in perform_transform, just reject result_promise
+ self.result_promise.reject(cx, v, can_gc);
+ }
+}
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+/// Reacting to rejection of backpressureChangePromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm>
+struct BackpressureChangeRejection {
+ #[ignore_malloc_size_of = "Rc is hard"]
+ result_promise: Rc<Promise>,
+}
+
+impl Callback for BackpressureChangeRejection {
+ fn callback(&self, cx: SafeJSContext, reason: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ self.result_promise.reject(cx, reason, can_gc);
+ }
+}
+
+impl js::gc::Rootable for CancelPromiseFulfillment {}
+
+/// Reacting to fulfillment of the cancelpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct CancelPromiseFulfillment {
+ readable: Dom<ReadableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+ #[ignore_malloc_size_of = "mozjs"]
+ reason: Box<Heap<JSVal>>,
+}
+
+impl Callback for CancelPromiseFulfillment {
+ /// Reacting to backpressureChangePromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // If readable.[[state]] is "errored", reject controller.[[finishPromise]] with readable.[[storedError]].
+ if self.readable.is_errored() {
+ rooted!(in(*cx) let mut error = UndefinedValue());
+ self.readable.get_stored_error(error.handle_mut());
+ self.controller
+ .get_finish_promise()
+ .expect("finish promise is not set")
+ .reject_native(&error.handle(), can_gc);
+ } else {
+ // Otherwise:
+ // Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], reason).
+ rooted!(in(*cx) let mut reason = UndefinedValue());
+ reason.set(self.reason.get());
+ self.readable
+ .get_default_controller()
+ .error(reason.handle(), can_gc);
+
+ // Resolve controller.[[finishPromise]] with undefined.
+ self.controller
+ .get_finish_promise()
+ .expect("finish promise is not set")
+ .resolve_native(&(), can_gc);
+ }
+ }
+}
+
+impl js::gc::Rootable for CancelPromiseRejection {}
+
+/// Reacting to rejection of cancelpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct CancelPromiseRejection {
+ readable: Dom<ReadableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+}
+
+impl Callback for CancelPromiseRejection {
+ /// Reacting to backpressureChangePromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], r).
+ self.readable.get_default_controller().error(v, can_gc);
+
+ // Reject controller.[[finishPromise]] with r.
+ self.controller
+ .get_finish_promise()
+ .expect("finish promise is not set")
+ .reject(cx, v, can_gc);
+ }
+}
+
+impl js::gc::Rootable for SourceCancelPromiseFulfillment {}
+
+/// Reacting to fulfillment of the cancelpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-source-cancel>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct SourceCancelPromiseFulfillment {
+ writeable: Dom<WritableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+ stream: Dom<TransformStream>,
+ #[ignore_malloc_size_of = "mozjs"]
+ reason: Box<Heap<JSVal>>,
+}
+
+impl Callback for SourceCancelPromiseFulfillment {
+ /// Reacting to backpressureChangePromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // If cancelPromise was fulfilled, then:
+ let finish_promise = self
+ .controller
+ .get_finish_promise()
+ .expect("finish promise is not set");
+
+ let global = &self.writeable.global();
+ // If writable.[[state]] is "errored", reject controller.[[finishPromise]] with writable.[[storedError]].
+ if self.writeable.is_errored() {
+ rooted!(in(*cx) let mut error = UndefinedValue());
+ self.writeable.get_stored_error(error.handle_mut());
+ finish_promise.reject(cx, error.handle(), can_gc);
+ } else {
+ // Otherwise:
+ // Perform ! WritableStreamDefaultControllerErrorIfNeeded(writable.[[controller]], reason).
+ rooted!(in(*cx) let mut reason = UndefinedValue());
+ reason.set(self.reason.get());
+ self.writeable.get_default_controller().error_if_needed(
+ cx,
+ reason.handle(),
+ global,
+ can_gc,
+ );
+
+ // Perform ! TransformStreamUnblockWrite(stream).
+ self.stream.unblock_write(global, can_gc);
+
+ // Resolve controller.[[finishPromise]] with undefined.
+ finish_promise.resolve_native(&(), can_gc);
+ }
+ }
+}
+
+impl js::gc::Rootable for SourceCancelPromiseRejection {}
+
+/// Reacting to rejection of cancelpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-source-cancel>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct SourceCancelPromiseRejection {
+ writeable: Dom<WritableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+ stream: Dom<TransformStream>,
+}
+
+impl Callback for SourceCancelPromiseRejection {
+ /// Reacting to backpressureChangePromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Perform ! WritableStreamDefaultControllerErrorIfNeeded(writable.[[controller]], r).
+ let global = &self.writeable.global();
+
+ self.writeable
+ .get_default_controller()
+ .error_if_needed(cx, v, global, can_gc);
+
+ // Perform ! TransformStreamUnblockWrite(stream).
+ self.stream.unblock_write(global, can_gc);
+
+ // Reject controller.[[finishPromise]] with r.
+ self.controller
+ .get_finish_promise()
+ .expect("finish promise is not set")
+ .reject(cx, v, can_gc);
+ }
+}
+
+impl js::gc::Rootable for FlushPromiseFulfillment {}
+
+/// Reacting to fulfillment of the flushpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct FlushPromiseFulfillment {
+ readable: Dom<ReadableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+}
+
+impl Callback for FlushPromiseFulfillment {
+ /// Reacting to flushpromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, _v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // If flushPromise was fulfilled, then:
+ let finish_promise = self
+ .controller
+ .get_finish_promise()
+ .expect("finish promise is not set");
+
+ // If readable.[[state]] is "errored", reject controller.[[finishPromise]] with readable.[[storedError]].
+ if self.readable.is_errored() {
+ rooted!(in(*cx) let mut error = UndefinedValue());
+ self.readable.get_stored_error(error.handle_mut());
+ finish_promise.reject(cx, error.handle(), can_gc);
+ } else {
+ // Otherwise:
+ // Perform ! ReadableStreamDefaultControllerClose(readable.[[controller]]).
+ self.readable.get_default_controller().close(can_gc);
+
+ // Resolve controller.[[finishPromise]] with undefined.
+ finish_promise.resolve_native(&(), can_gc);
+ }
+ }
+}
+
+impl js::gc::Rootable for FlushPromiseRejection {}
+/// Reacting to rejection of flushpromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm>
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct FlushPromiseRejection {
+ readable: Dom<ReadableStream>,
+ controller: Dom<TransformStreamDefaultController>,
+}
+
+impl Callback for FlushPromiseRejection {
+ /// Reacting to flushpromise with the following fulfillment steps:
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // If flushPromise was rejected with reason r, then:
+ // Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], r).
+ self.readable.get_default_controller().error(v, can_gc);
+
+ // Reject controller.[[finishPromise]] with r.
+ self.controller
+ .get_finish_promise()
+ .expect("finish promise is not set")
+ .reject(cx, v, can_gc);
+ }
+}
+
+/// <https://streams.spec.whatwg.org/#ts-class>
+#[dom_struct]
+pub struct TransformStream {
+ reflector_: Reflector,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-backpressure>
+ backpressure: Cell<bool>,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-backpressurechangepromise>
+ #[ignore_malloc_size_of = "Rc is hard"]
+ backpressure_change_promise: DomRefCell<Option<Rc<Promise>>>,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-controller>
+ controller: MutNullableDom<TransformStreamDefaultController>,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-detached>
+ detached: Cell<bool>,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-readable>
+ readable: MutNullableDom<ReadableStream>,
+
+ /// <https://streams.spec.whatwg.org/#transformstream-writable>
+ writable: MutNullableDom<WritableStream>,
+}
+
+impl TransformStream {
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ /// <https://streams.spec.whatwg.org/#initialize-transform-stream>
+ fn new_inherited() -> TransformStream {
+ TransformStream {
+ reflector_: Reflector::new(),
+ backpressure: Default::default(),
+ backpressure_change_promise: DomRefCell::new(None),
+ controller: MutNullableDom::new(None),
+ detached: Cell::new(false),
+ readable: MutNullableDom::new(None),
+ writable: MutNullableDom::new(None),
+ }
+ }
+
+ pub(crate) fn new_with_proto(
+ global: &GlobalScope,
+ proto: Option<SafeHandleObject>,
+ can_gc: CanGc,
+ ) -> DomRoot<TransformStream> {
+ reflect_dom_object_with_proto(
+ Box::new(TransformStream::new_inherited()),
+ global,
+ proto,
+ can_gc,
+ )
+ }
+
+ pub(crate) fn get_controller(&self) -> DomRoot<TransformStreamDefaultController> {
+ self.controller.get().expect("controller is not set")
+ }
+
+ pub(crate) fn get_writable(&self) -> DomRoot<WritableStream> {
+ self.writable.get().expect("writable stream is not set")
+ }
+
+ pub(crate) fn get_readable(&self) -> DomRoot<ReadableStream> {
+ self.readable.get().expect("readable stream is not set")
+ }
+
+ pub(crate) fn get_backpressure(&self) -> bool {
+ self.backpressure.get()
+ }
+
+ /// <https://streams.spec.whatwg.org/#initialize-transform-stream>
+ #[allow(clippy::too_many_arguments)]
+ fn initialize(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ start_promise: Rc<Promise>,
+ writable_high_water_mark: f64,
+ writable_size_algorithm: Rc<QueuingStrategySize>,
+ readable_high_water_mark: f64,
+ readable_size_algorithm: Rc<QueuingStrategySize>,
+ can_gc: CanGc,
+ ) -> Fallible<()> {
+ // Let startAlgorithm be an algorithm that returns startPromise.
+ // Let writeAlgorithm be the following steps, taking a chunk argument:
+ // Return ! TransformStreamDefaultSinkWriteAlgorithm(stream, chunk).
+ // Let abortAlgorithm be the following steps, taking a reason argument:
+ // Return ! TransformStreamDefaultSinkAbortAlgorithm(stream, reason).
+ // Let closeAlgorithm be the following steps:
+ // Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
+ // Set stream.[[writable]] to ! CreateWritableStream(startAlgorithm, writeAlgorithm,
+ // closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm).
+ // Note: Those steps are implemented using UnderlyingSinkType::Transform.
+
+ let writable = create_writable_stream(
+ cx,
+ global,
+ writable_high_water_mark,
+ writable_size_algorithm,
+ UnderlyingSinkType::Transform(Dom::from_ref(self), start_promise.clone()),
+ can_gc,
+ )?;
+ self.writable.set(Some(&writable));
+
+ // Let pullAlgorithm be the following steps:
+
+ // Return ! TransformStreamDefaultSourcePullAlgorithm(stream).
+
+ // Let cancelAlgorithm be the following steps, taking a reason argument:
+
+ // Return ! TransformStreamDefaultSourceCancelAlgorithm(stream, reason).
+
+ // Set stream.[[readable]] to ! CreateReadableStream(startAlgorithm, pullAlgorithm,
+ // cancelAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
+
+ let readable = create_readable_stream(
+ global,
+ UnderlyingSourceType::Transform(Dom::from_ref(self), start_promise.clone()),
+ Some(readable_size_algorithm),
+ Some(readable_high_water_mark),
+ can_gc,
+ );
+ self.readable.set(Some(&readable));
+
+ // Set stream.[[backpressure]] and stream.[[backpressureChangePromise]] to undefined.
+ // Note: This is done in the constructor.
+
+ // Perform ! TransformStreamSetBackpressure(stream, true).
+ self.set_backpressure(global, true, can_gc);
+
+ // Set stream.[[controller]] to undefined.
+ self.controller.set(None);
+
+ Ok(())
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-set-backpressure>
+ pub(crate) fn set_backpressure(&self, global: &GlobalScope, backpressure: bool, can_gc: CanGc) {
+ // Assert: stream.[[backpressure]] is not backpressure.
+ assert!(self.backpressure.get() != backpressure);
+
+ // If stream.[[backpressureChangePromise]] is not undefined, resolve
+ // stream.[[backpressureChangePromise]] with undefined.
+ if let Some(promise) = self.backpressure_change_promise.borrow_mut().take() {
+ promise.resolve_native(&(), can_gc);
+ }
+
+ // Set stream.[[backpressureChangePromise]] to a new promise.;
+ *self.backpressure_change_promise.borrow_mut() = Some(Promise::new(global, can_gc));
+
+ // Set stream.[[backpressure]] to backpressure.
+ self.backpressure.set(backpressure);
+ }
+
+ /// <https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller>
+ fn set_up_transform_stream_default_controller(
+ &self,
+ controller: &TransformStreamDefaultController,
+ ) {
+ // Assert: stream implements TransformStream.
+ // Note: this is checked with type.
+
+ // Assert: stream.[[controller]] is undefined.
+ assert!(self.controller.get().is_none());
+
+ // Set controller.[[stream]] to stream.
+ controller.set_stream(self);
+
+ // Set stream.[[controller]] to controller.
+ self.controller.set(Some(controller));
+
+ // Set controller.[[transformAlgorithm]] to transformAlgorithm.
+ // Set controller.[[flushAlgorithm]] to flushAlgorithm.
+ // Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
+ // Note: These are set in the constructor.
+ }
+
+ /// <https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer>
+ fn set_up_transform_stream_default_controller_from_transformer(
+ &self,
+ global: &GlobalScope,
+ transformer_obj: SafeHandleObject,
+ transformer: &Transformer,
+ can_gc: CanGc,
+ ) {
+ // Let controller be a new TransformStreamDefaultController.
+ let controller = TransformStreamDefaultController::new(global, transformer, can_gc);
+
+ // Let transformAlgorithm be the following steps, taking a chunk argument:
+ // Let result be TransformStreamDefaultControllerEnqueue(controller, chunk).
+ // If result is an abrupt completion, return a promise rejected with result.[[Value]].
+ // Otherwise, return a promise resolved with undefined.
+
+ // Let flushAlgorithm be an algorithm which returns a promise resolved with undefined.
+ // Let cancelAlgorithm be an algorithm which returns a promise resolved with undefined.
+
+ // If transformerDict["transform"] exists, set transformAlgorithm to an algorithm which
+ // takes an argument
+ // chunk and returns the result of invoking transformerDict["transform"] with argument
+ // list « chunk, controller »
+ // and callback this value transformer.
+
+ // If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns
+ // the result
+ // of invoking transformerDict["flush"] with argument list « controller » and callback
+ // this value transformer.
+
+ // If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument
+ // reason and returns the result of invoking transformerDict["cancel"] with argument list « reason »
+ // and callback this value transformer.
+ controller.set_transform_obj(transformer_obj);
+
+ // Perform ! SetUpTransformStreamDefaultController(stream, controller,
+ // transformAlgorithm, flushAlgorithm, cancelAlgorithm).
+ self.set_up_transform_stream_default_controller(&controller);
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm>
+ pub(crate) fn transform_stream_default_sink_write_algorithm(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ chunk: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Assert: stream.[[writable]].[[state]] is "writable".
+ assert!(self.writable.get().is_some());
+
+ // Let controller be stream.[[controller]].
+ let controller = self.controller.get().expect("controller is not set");
+
+ // If stream.[[backpressure]] is true,
+ if self.backpressure.get() {
+ // Let backpressureChangePromise be stream.[[backpressureChangePromise]].
+ let backpressure_change_promise = self.backpressure_change_promise.borrow();
+
+ // Assert: backpressureChangePromise is not undefined.
+ assert!(backpressure_change_promise.is_some());
+
+ // Return the result of reacting to backpressureChangePromise with the following fulfillment steps:
+ let result_promise = Promise::new(global, can_gc);
+ rooted!(in(*cx) let mut fulfillment_handler = Some(TransformBackPressureChangePromiseFulfillment {
+ controller: Dom::from_ref(&controller),
+ writable: Dom::from_ref(&self.writable.get().expect("writable stream")),
+ chunk: Heap::boxed(chunk.get()),
+ result_promise: result_promise.clone(),
+ }));
+
+ let handler = PromiseNativeHandler::new(
+ global,
+ fulfillment_handler.take().map(|h| Box::new(h) as Box<_>),
+ Some(Box::new(BackpressureChangeRejection {
+ result_promise: result_promise.clone(),
+ })),
+ can_gc,
+ );
+ let realm = enter_realm(global);
+ let comp = InRealm::Entered(&realm);
+ backpressure_change_promise
+ .as_ref()
+ .expect("Promise must be some by now.")
+ .append_native_handler(&handler, comp, can_gc);
+
+ return Ok(result_promise);
+ }
+
+ // Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
+ controller.transform_stream_default_controller_perform_transform(cx, global, chunk, can_gc)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm>
+ pub(crate) fn transform_stream_default_sink_abort_algorithm(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ reason: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Let controller be stream.[[controller]].
+ let controller = self.controller.get().expect("controller is not set");
+
+ // If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
+ if let Some(finish_promise) = controller.get_finish_promise() {
+ return Ok(finish_promise);
+ }
+
+ // Let readable be stream.[[readable]].
+ let readable = self.readable.get().expect("readable stream is not set");
+
+ // Let controller.[[finishPromise]] be a new promise.
+ controller.set_finish_promise(Promise::new(global, can_gc));
+
+ // Let cancelPromise be the result of performing controller.[[cancelAlgorithm]], passing reason.
+ let cancel_promise = controller.perform_cancel(cx, global, reason, can_gc)?;
+
+ // Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
+ controller.clear_algorithms();
+
+ // React to cancelPromise:
+ let handler = PromiseNativeHandler::new(
+ global,
+ Some(Box::new(CancelPromiseFulfillment {
+ readable: Dom::from_ref(&readable),
+ controller: Dom::from_ref(&controller),
+ reason: Heap::boxed(reason.get()),
+ })),
+ Some(Box::new(CancelPromiseRejection {
+ readable: Dom::from_ref(&readable),
+ controller: Dom::from_ref(&controller),
+ })),
+ can_gc,
+ );
+ let realm = enter_realm(global);
+ let comp = InRealm::Entered(&realm);
+ cancel_promise.append_native_handler(&handler, comp, can_gc);
+
+ // Return controller.[[finishPromise]].
+ let finish_promise = controller
+ .get_finish_promise()
+ .expect("finish promise is not set");
+ Ok(finish_promise)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm>
+ pub(crate) fn transform_stream_default_sink_close_algorithm(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Let controller be stream.[[controller]].
+ let controller = self
+ .controller
+ .get()
+ .ok_or(Error::Type("controller is not set".to_string()))?;
+
+ // If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
+ if let Some(finish_promise) = controller.get_finish_promise() {
+ return Ok(finish_promise);
+ }
+
+ // Let readable be stream.[[readable]].
+ let readable = self
+ .readable
+ .get()
+ .ok_or(Error::Type("readable stream is not set".to_string()))?;
+
+ // Let controller.[[finishPromise]] be a new promise.
+ controller.set_finish_promise(Promise::new(global, can_gc));
+
+ // Let flushPromise be the result of performing controller.[[flushAlgorithm]].
+ let flush_promise = controller.perform_flush(cx, global, can_gc)?;
+
+ // Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
+ controller.clear_algorithms();
+
+ // React to flushPromise:
+ let handler = PromiseNativeHandler::new(
+ global,
+ Some(Box::new(FlushPromiseFulfillment {
+ readable: Dom::from_ref(&readable),
+ controller: Dom::from_ref(&controller),
+ })),
+ Some(Box::new(FlushPromiseRejection {
+ readable: Dom::from_ref(&readable),
+ controller: Dom::from_ref(&controller),
+ })),
+ can_gc,
+ );
+
+ let realm = enter_realm(global);
+ let comp = InRealm::Entered(&realm);
+ flush_promise.append_native_handler(&handler, comp, can_gc);
+ // Return controller.[[finishPromise]].
+ let finish_promise = controller
+ .get_finish_promise()
+ .expect("finish promise is not set");
+ Ok(finish_promise)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-source-cancel>
+ pub(crate) fn transform_stream_default_source_cancel(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ reason: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Let controller be stream.[[controller]].
+ let controller = self
+ .controller
+ .get()
+ .ok_or(Error::Type("controller is not set".to_string()))?;
+
+ // If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
+ if let Some(finish_promise) = controller.get_finish_promise() {
+ return Ok(finish_promise);
+ }
+
+ // Let writable be stream.[[writable]].
+ let writable = self
+ .writable
+ .get()
+ .ok_or(Error::Type("writable stream is not set".to_string()))?;
+
+ // Let controller.[[finishPromise]] be a new promise.
+ controller.set_finish_promise(Promise::new(global, can_gc));
+
+ // Let cancelPromise be the result of performing controller.[[cancelAlgorithm]], passing reason.
+ let cancel_promise = controller.perform_cancel(cx, global, reason, can_gc)?;
+
+ // Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
+ controller.clear_algorithms();
+
+ // React to cancelPromise:
+ let handler = PromiseNativeHandler::new(
+ global,
+ Some(Box::new(SourceCancelPromiseFulfillment {
+ writeable: Dom::from_ref(&writable),
+ controller: Dom::from_ref(&controller),
+ stream: Dom::from_ref(self),
+ reason: Heap::boxed(reason.get()),
+ })),
+ Some(Box::new(SourceCancelPromiseRejection {
+ writeable: Dom::from_ref(&writable),
+ controller: Dom::from_ref(&controller),
+ stream: Dom::from_ref(self),
+ })),
+ can_gc,
+ );
+
+ // Return controller.[[finishPromise]].
+ let finish_promise = controller
+ .get_finish_promise()
+ .expect("finish promise is not set");
+ let realm = enter_realm(global);
+ let comp = InRealm::Entered(&realm);
+ cancel_promise.append_native_handler(&handler, comp, can_gc);
+ Ok(finish_promise)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-source-pull>
+ pub(crate) fn transform_stream_default_source_pull(
+ &self,
+ global: &GlobalScope,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Assert: stream.[[backpressure]] is true.
+ assert!(self.backpressure.get());
+
+ // Assert: stream.[[backpressureChangePromise]] is not undefined.
+ assert!(self.backpressure_change_promise.borrow().is_some());
+
+ // Perform ! TransformStreamSetBackpressure(stream, false).
+ self.set_backpressure(global, false, can_gc);
+
+ // Return stream.[[backpressureChangePromise]].
+ Ok(self
+ .backpressure_change_promise
+ .borrow()
+ .clone()
+ .expect("Promise must be some by now."))
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-error-writable-and-unblock-write>
+ pub(crate) fn error_writable_and_unblock_write(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ error: SafeHandleValue,
+ can_gc: CanGc,
+ ) {
+ // Perform ! TransformStreamDefaultControllerClearAlgorithms(stream.[[controller]]).
+ self.get_controller().clear_algorithms();
+
+ // Perform ! WritableStreamDefaultControllerErrorIfNeeded(stream.[[writable]].[[controller]], e).
+ self.get_writable()
+ .get_default_controller()
+ .error_if_needed(cx, error, global, can_gc);
+
+ // Perform ! TransformStreamUnblockWrite(stream).
+ self.unblock_write(global, can_gc)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-unblock-write>
+ pub(crate) fn unblock_write(&self, global: &GlobalScope, can_gc: CanGc) {
+ // If stream.[[backpressure]] is true, perform ! TransformStreamSetBackpressure(stream, false).
+ if self.backpressure.get() {
+ self.set_backpressure(global, false, can_gc);
+ }
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-error>
+ pub(crate) fn error(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ error: SafeHandleValue,
+ can_gc: CanGc,
+ ) {
+ // Perform ! ReadableStreamDefaultControllerError(stream.[[readable]].[[controller]], e).
+ self.get_readable()
+ .get_default_controller()
+ .error(error, can_gc);
+
+ // Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, e).
+ self.error_writable_and_unblock_write(cx, global, error, can_gc);
+ }
+}
+
+impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
+ /// <https://streams.spec.whatwg.org/#ts-constructor>
+ #[allow(unsafe_code)]
+ fn Constructor(
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ proto: Option<SafeHandleObject>,
+ can_gc: CanGc,
+ transformer: Option<*mut JSObject>,
+ writable_strategy: &QueuingStrategy,
+ readable_strategy: &QueuingStrategy,
+ ) -> Fallible<DomRoot<TransformStream>> {
+ // If transformer is missing, set it to null.
+ rooted!(in(*cx) let transformer_obj = transformer.unwrap_or(ptr::null_mut()));
+
+ // Let underlyingSinkDict be underlyingSink,
+ // converted to an IDL value of type UnderlyingSink.
+ let transformer_dict = if !transformer_obj.is_null() {
+ rooted!(in(*cx) let obj_val = ObjectValue(transformer_obj.get()));
+ match Transformer::new(cx, obj_val.handle()) {
+ Ok(ConversionResult::Success(val)) => val,
+ Ok(ConversionResult::Failure(error)) => return Err(Error::Type(error.to_string())),
+ _ => {
+ return Err(Error::JSFailed);
+ },
+ }
+ } else {
+ Transformer::empty()
+ };
+
+ // If transformerDict["readableType"] exists, throw a RangeError exception.
+ if !transformer_dict.readableType.handle().is_undefined() {
+ return Err(Error::Range("readableType is set".to_string()));
+ }
+
+ // If transformerDict["writableType"] exists, throw a RangeError exception.
+ if !transformer_dict.writableType.handle().is_undefined() {
+ return Err(Error::Range("writableType is set".to_string()));
+ }
+
+ // Let readableHighWaterMark be ? ExtractHighWaterMark(readableStrategy, 0).
+ let readable_high_water_mark = extract_high_water_mark(readable_strategy, 0.0)?;
+
+ // Let readableSizeAlgorithm be ! ExtractSizeAlgorithm(readableStrategy).
+ let readable_size_algorithm = extract_size_algorithm(readable_strategy, can_gc);
+
+ // Let writableHighWaterMark be ? ExtractHighWaterMark(writableStrategy, 1).
+ let writable_high_water_mark = extract_high_water_mark(writable_strategy, 1.0)?;
+
+ // Let writableSizeAlgorithm be ! ExtractSizeAlgorithm(writableStrategy).
+ let writable_size_algorithm = extract_size_algorithm(writable_strategy, can_gc);
+
+ // Let startPromise be a new promise.
+ let start_promise = Promise::new(global, can_gc);
+
+ // Perform ! InitializeTransformStream(this, startPromise, writableHighWaterMark,
+ // writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
+ let stream = TransformStream::new_with_proto(global, proto, can_gc);
+ stream.initialize(
+ cx,
+ global,
+ start_promise.clone(),
+ writable_high_water_mark,
+ writable_size_algorithm,
+ readable_high_water_mark,
+ readable_size_algorithm,
+ can_gc,
+ )?;
+
+ // Perform ? SetUpTransformStreamDefaultControllerFromTransformer(this, transformer, transformerDict).
+ stream.set_up_transform_stream_default_controller_from_transformer(
+ global,
+ transformer_obj.handle(),
+ &transformer_dict,
+ can_gc,
+ );
+
+ // If transformerDict["start"] exists, then resolve startPromise with the
+ // result of invoking transformerDict["start"]
+ // with argument list « this.[[controller]] » and callback this value transformer.
+ if let Some(start) = &transformer_dict.start {
+ rooted!(in(*cx) let mut result_object = ptr::null_mut::<JSObject>());
+ rooted!(in(*cx) let mut result: JSVal);
+ rooted!(in(*cx) let this_object = transformer_obj.get());
+ start.Call_(
+ &this_object.handle(),
+ &stream.get_controller(),
+ result.handle_mut(),
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )?;
+ let is_promise = unsafe {
+ if result.is_object() {
+ result_object.set(result.to_object());
+ IsPromiseObject(result_object.handle().into_handle())
+ } else {
+ false
+ }
+ };
+ let promise = if is_promise {
+ let promise = Promise::new_with_js_promise(result_object.handle(), cx);
+ promise
+ } else {
+ Promise::new_resolved(global, cx, result.get(), can_gc)
+ };
+ start_promise.resolve_native(&promise, can_gc);
+ } else {
+ // Otherwise, resolve startPromise with undefined.
+ start_promise.resolve_native(&(), can_gc);
+ };
+
+ Ok(stream)
+ }
+
+ /// <https://streams.spec.whatwg.org/#ts-readable>
+ fn Readable(&self) -> DomRoot<ReadableStream> {
+ // Return this.[[readable]].
+ self.readable.get().expect("readable stream is not set")
+ }
+
+ /// <https://streams.spec.whatwg.org/#ts-writable>
+ fn Writable(&self) -> DomRoot<WritableStream> {
+ // Return this.[[writable]].
+ self.writable.get().expect("writable stream is not set")
+ }
+}
diff --git a/components/script/dom/transformstreamdefaultcontroller.rs b/components/script/dom/transformstreamdefaultcontroller.rs
new file mode 100644
index 00000000000..41813ef6f96
--- /dev/null
+++ b/components/script/dom/transformstreamdefaultcontroller.rs
@@ -0,0 +1,420 @@
+/* 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::cell::RefCell;
+use std::rc::Rc;
+
+use dom_struct::dom_struct;
+use js::jsapi::{
+ ExceptionStackBehavior, Heap, JS_IsExceptionPending, JS_SetPendingException, JSObject,
+};
+use js::jsval::UndefinedValue;
+use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};
+
+use super::bindings::cell::DomRefCell;
+use super::bindings::codegen::Bindings::TransformerBinding::{
+ Transformer, TransformerCancelCallback, TransformerFlushCallback, TransformerTransformCallback,
+};
+use super::types::TransformStream;
+use crate::dom::bindings::callback::ExceptionHandling;
+use crate::dom::bindings::codegen::Bindings::TransformStreamDefaultControllerBinding::TransformStreamDefaultControllerMethods;
+use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
+use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
+use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::promise::Promise;
+use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
+use crate::realms::{InRealm, enter_realm};
+use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
+
+impl js::gc::Rootable for TransformTransformPromiseRejection {}
+
+/// Reacting to transformPromise as part of
+/// <https://streams.spec.whatwg.org/#transform-stream-default-controller-perform-transform>
+#[derive(JSTraceable, MallocSizeOf)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+struct TransformTransformPromiseRejection {
+ controller: Dom<TransformStreamDefaultController>,
+}
+
+impl Callback for TransformTransformPromiseRejection {
+ /// Reacting to transformPromise with the following fulfillment steps:
+ #[allow(unsafe_code)]
+ fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
+ // Perform ! TransformStreamError(controller.[[stream]], r).
+ self.controller
+ .error(cx, &self.controller.global(), v, can_gc);
+
+ // Throw r.
+ // Note: this is done part of perform_transform().
+ }
+}
+
+/// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller>
+#[dom_struct]
+pub struct TransformStreamDefaultController {
+ reflector_: Reflector,
+
+ /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-cancelalgorithm>
+ #[ignore_malloc_size_of = "Rc is hard"]
+ cancel: RefCell<Option<Rc<TransformerCancelCallback>>>,
+
+ /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-flushalgorithm>
+ #[ignore_malloc_size_of = "Rc is hard"]
+ flush: RefCell<Option<Rc<TransformerFlushCallback>>>,
+
+ /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-transformalgorithm>
+ #[ignore_malloc_size_of = "Rc is hard"]
+ transform: RefCell<Option<Rc<TransformerTransformCallback>>>,
+
+ /// The JS object used as `this` when invoking sink algorithms.
+ #[ignore_malloc_size_of = "mozjs"]
+ transform_obj: Heap<*mut JSObject>,
+
+ /// <https://streams.spec.whatwg.org/#TransformStreamDefaultController-stream>
+ stream: MutNullableDom<TransformStream>,
+
+ /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-finishpromise>
+ #[ignore_malloc_size_of = "Rc is hard"]
+ finish_promise: DomRefCell<Option<Rc<Promise>>>,
+}
+
+impl TransformStreamDefaultController {
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ fn new_inherited(transformer: &Transformer) -> TransformStreamDefaultController {
+ TransformStreamDefaultController {
+ reflector_: Reflector::new(),
+ cancel: RefCell::new(transformer.cancel.clone()),
+ flush: RefCell::new(transformer.flush.clone()),
+ transform: RefCell::new(transformer.transform.clone()),
+ finish_promise: DomRefCell::new(None),
+ stream: MutNullableDom::new(None),
+ transform_obj: Default::default(),
+ }
+ }
+
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ pub(crate) fn new(
+ global: &GlobalScope,
+ transformer: &Transformer,
+ can_gc: CanGc,
+ ) -> DomRoot<TransformStreamDefaultController> {
+ reflect_dom_object(
+ Box::new(TransformStreamDefaultController::new_inherited(transformer)),
+ global,
+ can_gc,
+ )
+ }
+
+ /// Setting the JS object after the heap has settled down.
+ pub(crate) fn set_transform_obj(&self, this_object: SafeHandleObject) {
+ self.transform_obj.set(*this_object);
+ }
+
+ pub(crate) fn set_stream(&self, stream: &TransformStream) {
+ self.stream.set(Some(stream));
+ }
+
+ pub(crate) fn get_finish_promise(&self) -> Option<Rc<Promise>> {
+ self.finish_promise.borrow().clone()
+ }
+
+ pub(crate) fn set_finish_promise(&self, promise: Rc<Promise>) {
+ *self.finish_promise.borrow_mut() = Some(promise);
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-perform-transform>
+ pub(crate) fn transform_stream_default_controller_perform_transform(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ chunk: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // Let transformPromise be the result of performing controller.[[transformAlgorithm]], passing chunk.
+ let transform_promise = self.perform_transform(cx, global, chunk, can_gc)?;
+
+ // Return the result of reacting to transformPromise with the following rejection steps given the argument r:
+ rooted!(in(*cx) let mut reject_handler = Some(TransformTransformPromiseRejection {
+ controller: Dom::from_ref(self),
+ }));
+
+ let handler = PromiseNativeHandler::new(
+ global,
+ None,
+ reject_handler.take().map(|h| Box::new(h) as Box<_>),
+ can_gc,
+ );
+ let realm = enter_realm(global);
+ let comp = InRealm::Entered(&realm);
+ transform_promise.append_native_handler(&handler, comp, can_gc);
+
+ Ok(transform_promise)
+ }
+
+ pub(crate) fn perform_transform(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ chunk: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // If transformerDict["transform"] exists, set transformAlgorithm to an algorithm which
+ // takes an argument chunk and returns the result of invoking transformerDict["transform"] with argument list
+ // « chunk, controller » and callback this value transformer.
+ let algo = self.transform.borrow().clone();
+ let result = if let Some(transform) = algo {
+ rooted!(in(*cx) let this_object = self.transform_obj.get());
+ let call_result = transform.Call_(
+ &this_object.handle(),
+ chunk,
+ self,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ );
+ match call_result {
+ Ok(p) => p,
+ Err(e) => {
+ let p = Promise::new(global, can_gc);
+ p.reject_error(e, can_gc);
+ p
+ },
+ }
+ } else {
+ // Let transformAlgorithm be the following steps, taking a chunk argument:
+ // Let result be TransformStreamDefaultControllerEnqueue(controller, chunk).
+ // If result is an abrupt completion, return a promise rejected with result.[[Value]].
+ let promise = if let Err(error) = self.enqueue(cx, global, chunk, can_gc) {
+ rooted!(in(*cx) let mut error_val = UndefinedValue());
+ error.to_jsval(cx, global, error_val.handle_mut(), can_gc);
+ Promise::new_rejected(global, cx, error_val.handle(), can_gc)
+ } else {
+ // Otherwise, return a promise resolved with undefined.
+ Promise::new_resolved(global, cx, (), can_gc)
+ };
+
+ promise
+ };
+
+ Ok(result)
+ }
+
+ pub(crate) fn perform_cancel(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ chunk: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument
+ // reason and returns the result of invoking transformerDict["cancel"] with argument list « reason »
+ // and callback this value transformer.
+ let algo = self.cancel.borrow().clone();
+ let result = if let Some(cancel) = algo {
+ rooted!(in(*cx) let this_object = self.transform_obj.get());
+ let call_result = cancel.Call_(
+ &this_object.handle(),
+ chunk,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ );
+ match call_result {
+ Ok(p) => p,
+ Err(e) => {
+ let p = Promise::new(global, can_gc);
+ p.reject_error(e, can_gc);
+ p
+ },
+ }
+ } else {
+ // Let cancelAlgorithm be an algorithm which returns a promise resolved with undefined.
+ Promise::new_resolved(global, cx, (), can_gc)
+ };
+
+ Ok(result)
+ }
+
+ pub(crate) fn perform_flush(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ // If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of
+ // invoking transformerDict["flush"] with argument list « controller » and callback this value transformer.
+ let algo = self.flush.borrow().clone();
+ let result = if let Some(flush) = algo {
+ rooted!(in(*cx) let this_object = self.transform_obj.get());
+ let call_result = flush.Call_(
+ &this_object.handle(),
+ self,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ );
+ match call_result {
+ Ok(p) => p,
+ Err(e) => {
+ let p = Promise::new(global, can_gc);
+ p.reject_error(e, can_gc);
+ p
+ },
+ }
+ } else {
+ // Let flushAlgorithm be an algorithm which returns a promise resolved with undefined.
+ Promise::new_resolved(global, cx, (), can_gc)
+ };
+
+ Ok(result)
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue>
+ #[allow(unsafe_code)]
+ pub(crate) fn enqueue(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ chunk: SafeHandleValue,
+ can_gc: CanGc,
+ ) -> Fallible<()> {
+ // Let stream be controller.[[stream]].
+ let stream = self.stream.get().expect("stream is null");
+
+ // Let readableController be stream.[[readable]].[[controller]].
+ let readable = stream.get_readable();
+ let readable_controller = readable.get_default_controller();
+
+ // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)
+ // is false, throw a TypeError exception.
+ if !readable_controller.can_close_or_enqueue() {
+ return Err(Error::Type(
+ "ReadableStreamDefaultControllerCanCloseOrEnqueue is false".to_owned(),
+ ));
+ }
+
+ // Let enqueueResult be ReadableStreamDefaultControllerEnqueue(readableController, chunk).
+ // If enqueueResult is an abrupt completion,
+ if let Err(error) = readable_controller.enqueue(cx, chunk, can_gc) {
+ // Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, enqueueResult.[[Value]]).
+ rooted!(in(*cx) let mut rooted_error = UndefinedValue());
+ error
+ .clone()
+ .to_jsval(cx, global, rooted_error.handle_mut(), can_gc);
+ stream.error_writable_and_unblock_write(cx, global, rooted_error.handle(), can_gc);
+
+ // Throw stream.[[readable]].[[storedError]].
+ unsafe {
+ if !JS_IsExceptionPending(*cx) {
+ rooted!(in(*cx) let mut stored_error = UndefinedValue());
+ readable.get_stored_error(stored_error.handle_mut());
+
+ JS_SetPendingException(
+ *cx,
+ stored_error.handle().into(),
+ ExceptionStackBehavior::Capture,
+ );
+ }
+ }
+ return Err(error);
+ }
+
+ // Let backpressure be ! ReadableStreamDefaultControllerHasBackpressure(readableController).
+ let backpressure = readable_controller.has_backpressure();
+
+ // If backpressure is not stream.[[backpressure]],
+ if backpressure != stream.get_backpressure() {
+ // Assert: backpressure is true.
+ assert!(backpressure);
+
+ // Perform ! TransformStreamSetBackpressure(stream, true).
+ stream.set_backpressure(global, true, can_gc);
+ }
+ Ok(())
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-error>
+ pub(crate) fn error(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ reason: SafeHandleValue,
+ can_gc: CanGc,
+ ) {
+ // Perform ! TransformStreamError(controller.[[stream]], e).
+ self.stream
+ .get()
+ .expect("stream is undefined")
+ .error(cx, global, reason, can_gc);
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-clear-algorithms>
+ pub(crate) fn clear_algorithms(&self) {
+ // Set controller.[[transformAlgorithm]] to undefined.
+ self.transform.replace(None);
+
+ // Set controller.[[flushAlgorithm]] to undefined.
+ self.flush.replace(None);
+
+ // Set controller.[[cancelAlgorithm]] to undefined.
+ self.cancel.replace(None);
+ }
+
+ /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate>
+ pub(crate) fn terminate(&self, cx: SafeJSContext, global: &GlobalScope, can_gc: CanGc) {
+ // Let stream be controller.[[stream]].
+ let stream = self.stream.get().expect("stream is null");
+
+ // Let readableController be stream.[[readable]].[[controller]].
+ let readable = stream.get_readable();
+ let readable_controller = readable.get_default_controller();
+
+ // Perform ! ReadableStreamDefaultControllerClose(readableController).
+ readable_controller.close(can_gc);
+
+ // Let error be a TypeError exception indicating that the stream has been terminated.
+ let error = Error::Type("stream has been terminated".to_owned());
+
+ // Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, error).
+ rooted!(in(*cx) let mut rooted_error = UndefinedValue());
+ error.to_jsval(cx, global, rooted_error.handle_mut(), can_gc);
+ stream.error_writable_and_unblock_write(cx, global, rooted_error.handle(), can_gc);
+ }
+}
+
+impl TransformStreamDefaultControllerMethods<crate::DomTypeHolder>
+ for TransformStreamDefaultController
+{
+ /// <https://streams.spec.whatwg.org/#ts-default-controller-desired-size>
+ fn GetDesiredSize(&self) -> Option<f64> {
+ // Let readableController be this.[[stream]].[[readable]].[[controller]].
+ let readable_controller = self
+ .stream
+ .get()
+ .expect("stream is null")
+ .get_readable()
+ .get_default_controller();
+
+ // Return ! ReadableStreamDefaultControllerGetDesiredSize(readableController).
+ readable_controller.get_desired_size()
+ }
+
+ /// <https://streams.spec.whatwg.org/#ts-default-controller-enqueue>
+ fn Enqueue(&self, cx: SafeJSContext, chunk: SafeHandleValue, can_gc: CanGc) -> Fallible<()> {
+ // Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
+ self.enqueue(cx, &self.global(), chunk, can_gc)
+ }
+
+ /// <https://streams.spec.whatwg.org/#ts-default-controller-error>
+ fn Error(&self, cx: SafeJSContext, reason: SafeHandleValue, can_gc: CanGc) -> Fallible<()> {
+ // Perform ? TransformStreamDefaultControllerError(this, e).
+ self.error(cx, &self.global(), reason, can_gc);
+ Ok(())
+ }
+
+ /// <https://streams.spec.whatwg.org/#ts-default-controller-terminate>
+ fn Terminate(&self, can_gc: CanGc) -> Fallible<()> {
+ // Perform ? TransformStreamDefaultControllerTerminate(this).
+ self.terminate(GlobalScope::get_cx(), &self.global(), can_gc);
+ Ok(())
+ }
+}
diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs
index 0927446b904..284fa7045eb 100644
--- a/components/script/dom/trustedtypepolicyfactory.rs
+++ b/components/script/dom/trustedtypepolicyfactory.rs
@@ -66,7 +66,7 @@ impl TrustedTypePolicyFactory {
(CheckResult::Allowed, Vec::new())
};
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
// Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
if allowed_by_csp == CheckResult::Blocked {
@@ -230,7 +230,7 @@ impl TrustedTypePolicyFactory {
.should_sink_type_mismatch_violation_be_blocked_by_csp(
sink, sink_group, &input,
);
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
// Step 6.2: If disposition is “Allowed”, return stringified input and abort further steps.
if disposition == CheckResult::Allowed {
Ok(input)
diff --git a/components/script/dom/underlyingsourcecontainer.rs b/components/script/dom/underlyingsourcecontainer.rs
index 4acb58bafef..dd4b867df45 100644
--- a/components/script/dom/underlyingsourcecontainer.rs
+++ b/components/script/dom/underlyingsourcecontainer.rs
@@ -20,6 +20,7 @@ use crate::dom::defaultteeunderlyingsource::DefaultTeeUnderlyingSource;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use crate::dom::promise::Promise;
+use crate::dom::transformstream::TransformStream;
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
/// <https://streams.spec.whatwg.org/#underlying-source-api>
@@ -46,8 +47,7 @@ pub(crate) enum UnderlyingSourceType {
/// A struct representing a JS object as underlying source,
/// and the actual JS object for use as `thisArg` in callbacks.
/// This is used for the `TransformStream` API.
- #[allow(unused)]
- Transform(/* Dom<TransformStream>, Rc<Promise>*/),
+ Transform(Dom<TransformStream>, Rc<Promise>),
}
impl UnderlyingSourceType {
@@ -139,9 +139,9 @@ impl UnderlyingSourceContainer {
// Call the cancel algorithm for the appropriate branch.
tee_underlying_source.cancel_algorithm(cx, global, reason, can_gc)
},
- UnderlyingSourceType::Transform() => {
+ UnderlyingSourceType::Transform(stream, _) => {
// Return ! TransformStreamDefaultSourceCancelAlgorithm(stream, reason).
- todo!();
+ Some(stream.transform_stream_default_source_cancel(cx, global, reason, can_gc))
},
UnderlyingSourceType::Transfer(port) => {
// Let cancelAlgorithm be the following steps, taking a reason argument:
@@ -213,9 +213,9 @@ impl UnderlyingSourceContainer {
Some(Ok(promise))
},
// Note: other source type have no pull steps for now.
- UnderlyingSourceType::Transform() => {
+ UnderlyingSourceType::Transform(stream, _) => {
// Return ! TransformStreamDefaultSourcePullAlgorithm(stream).
- todo!();
+ Some(stream.transform_stream_default_source_pull(&self.global(), can_gc))
},
_ => None,
}
@@ -280,9 +280,9 @@ impl UnderlyingSourceContainer {
// from <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
None
},
- UnderlyingSourceType::Transform() => {
- // Some(transform_underlying_source.start_algorithm())
- todo!();
+ UnderlyingSourceType::Transform(_, start_promise) => {
+ // Let startAlgorithm be an algorithm that returns startPromise.
+ Some(Ok(start_promise.clone()))
},
_ => None,
}
diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs
index b9b1b50c901..bbb637dfe28 100644
--- a/components/script/dom/websocket.rs
+++ b/components/script/dom/websocket.rs
@@ -471,7 +471,7 @@ struct ReportCSPViolationTask {
impl TaskOnce for ReportCSPViolationTask {
fn run_once(self) {
let global = self.websocket.root().global();
- global.report_csp_violations(self.violations);
+ global.report_csp_violations(self.violations, None);
}
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index d888cc8d917..24e694b4f06 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -65,6 +65,7 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan;
use script_bindings::codegen::GenericBindings::NavigatorBinding::NavigatorMethods;
use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMethods;
use script_bindings::interfaces::WindowHelpers;
+use script_bindings::root::Root;
use script_layout_interface::{
FragmentType, Layout, PendingImageState, QueryMsg, Reflow, ReflowGoal, ReflowRequest,
TrustedNodeAddress, combine_id_with_fragment_type,
@@ -146,6 +147,7 @@ use crate::dom::performance::Performance;
use crate::dom::promise::Promise;
use crate::dom::screen::Screen;
use crate::dom::selection::Selection;
+use crate::dom::shadowroot::ShadowRoot;
use crate::dom::storage::Storage;
#[cfg(feature = "bluetooth")]
use crate::dom::testrunner::TestRunner;
@@ -165,7 +167,7 @@ use crate::script_runtime::{CanGc, JSContext, Runtime};
use crate::script_thread::ScriptThread;
use crate::timers::{IsInterval, TimerCallback};
use crate::unminify::unminified_path;
-use crate::webdriver_handlers::jsval_to_webdriver;
+use crate::webdriver_handlers::{find_node_by_unique_id_in_document, jsval_to_webdriver};
use crate::{fetch, window_named_properties};
/// A callback to call when a response comes back from the `ImageCache`.
@@ -1394,6 +1396,30 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
}
}
+ fn WebdriverElement(&self, id: DOMString) -> Option<DomRoot<Element>> {
+ find_node_by_unique_id_in_document(&self.Document(), id.into())
+ .ok()
+ .and_then(Root::downcast)
+ }
+
+ fn WebdriverFrame(&self, id: DOMString) -> Option<DomRoot<Element>> {
+ find_node_by_unique_id_in_document(&self.Document(), id.into())
+ .ok()
+ .and_then(Root::downcast::<HTMLIFrameElement>)
+ .map(Root::upcast::<Element>)
+ }
+
+ fn WebdriverWindow(&self, _id: DOMString) -> Option<DomRoot<Window>> {
+ warn!("Window references are not supported in webdriver yet");
+ None
+ }
+
+ fn WebdriverShadowRoot(&self, id: DOMString) -> Option<DomRoot<ShadowRoot>> {
+ find_node_by_unique_id_in_document(&self.Document(), id.into())
+ .ok()
+ .and_then(Root::downcast)
+ }
+
// https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle
fn GetComputedStyle(
&self,
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs
index 1b029f592de..f528f4fbde2 100644
--- a/components/script/dom/writablestream.rs
+++ b/components/script/dom/writablestream.rs
@@ -962,14 +962,13 @@ impl WritableStream {
/// <https://streams.spec.whatwg.org/#create-writable-stream>
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
-#[allow(unused)]
pub(crate) fn create_writable_stream(
cx: SafeJSContext,
global: &GlobalScope,
- can_gc: CanGc,
writable_high_water_mark: f64,
writable_size_algorithm: Rc<QueuingStrategySize>,
underlying_sink_type: UnderlyingSinkType,
+ can_gc: CanGc,
) -> Fallible<DomRoot<WritableStream>> {
// Assert: ! IsNonNegativeNumber(highWaterMark) is true.
assert!(writable_high_water_mark >= 0.0);
diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs
index 084165a6892..135ee6faa59 100644
--- a/components/script/dom/writablestreamdefaultcontroller.rs
+++ b/components/script/dom/writablestreamdefaultcontroller.rs
@@ -12,6 +12,7 @@ use js::jsval::{JSVal, UndefinedValue};
use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue, IntoHandle};
use super::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategySize;
+use super::types::TransformStream;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::UnderlyingSinkBinding::{
UnderlyingSinkAbortCallback, UnderlyingSinkCloseCallback, UnderlyingSinkStartCallback,
@@ -290,8 +291,7 @@ pub enum UnderlyingSinkType {
port: Dom<MessagePort>,
},
/// Algorithms supporting transform streams are implemented in Rust.
- #[allow(unused)]
- Transform(/*Dom<TransformStream>, Rc<Promise>*/),
+ Transform(Dom<TransformStream>, Rc<Promise>),
}
impl UnderlyingSinkType {
@@ -413,7 +413,7 @@ impl WritableStreamDefaultController {
} => {
backpressure_promise.borrow_mut().take();
},
- UnderlyingSinkType::Transform() => {
+ UnderlyingSinkType::Transform(_, _) => {
return;
},
}
@@ -423,7 +423,6 @@ impl WritableStreamDefaultController {
}
/// <https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller>
- #[allow(unsafe_code)]
pub(crate) fn setup(
&self,
cx: SafeJSContext,
@@ -560,9 +559,9 @@ impl WritableStreamDefaultController {
// Let startAlgorithm be an algorithm that returns undefined.
Ok(Promise::new_resolved(global, cx, (), can_gc))
},
- UnderlyingSinkType::Transform() => {
+ UnderlyingSinkType::Transform(_, start_promise) => {
// Let startAlgorithm be an algorithm that returns startPromise.
- todo!()
+ Ok(start_promise.clone())
},
}
}
@@ -622,9 +621,11 @@ impl WritableStreamDefaultController {
}
promise
},
- UnderlyingSinkType::Transform() => {
+ UnderlyingSinkType::Transform(stream, _) => {
// Return ! TransformStreamDefaultSinkAbortAlgorithm(stream, reason).
- todo!()
+ stream
+ .transform_stream_default_sink_abort_algorithm(cx, global, reason, can_gc)
+ .expect("Transform stream default sink abort algorithm should not fail.")
},
};
@@ -707,9 +708,11 @@ impl WritableStreamDefaultController {
.append_native_handler(&handler, comp, can_gc);
result_promise
},
- UnderlyingSinkType::Transform() => {
+ UnderlyingSinkType::Transform(stream, _) => {
// Return ! TransformStreamDefaultSinkWriteAlgorithm(stream, chunk).
- todo!()
+ stream
+ .transform_stream_default_sink_write_algorithm(cx, global, chunk, can_gc)
+ .expect("Transform stream default sink write algorithm should not fail.")
},
}
}
@@ -757,9 +760,11 @@ impl WritableStreamDefaultController {
// Return a promise resolved with undefined.
Promise::new_resolved(global, cx, (), can_gc)
},
- UnderlyingSinkType::Transform() => {
+ UnderlyingSinkType::Transform(stream, _) => {
// Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
- todo!()
+ stream
+ .transform_stream_default_sink_close_algorithm(cx, global, can_gc)
+ .expect("Transform stream default sink close algorithm should not fail.")
},
}
}
@@ -1038,7 +1043,7 @@ impl WritableStreamDefaultController {
}
/// <https://streams.spec.whatwg.org/#writable-stream-default-controller-error>
- fn error(
+ pub(crate) fn error(
&self,
stream: &WritableStream,
cx: SafeJSContext,
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index 9cef58acc9a..ca5bb72a1dc 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -148,7 +148,7 @@ impl FetchResponseListener for XHRContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/fetch.rs b/components/script/fetch.rs
index 9192a030b66..989cdba862a 100644
--- a/components/script/fetch.rs
+++ b/components/script/fetch.rs
@@ -313,7 +313,7 @@ impl FetchResponseListener for FetchContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/layout_image.rs b/components/script/layout_image.rs
index df542b4b759..546e758e38c 100644
--- a/components/script/layout_image.rs
+++ b/components/script/layout_image.rs
@@ -81,7 +81,7 @@ impl FetchResponseListener for LayoutImageContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/script_module.rs b/components/script/script_module.rs
index 0aa35a2eda8..449f17901ed 100644
--- a/components/script/script_module.rs
+++ b/components/script/script_module.rs
@@ -1277,7 +1277,7 @@ impl FetchResponseListener for ModuleContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 1f05c15d74e..c407f9cfc73 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -390,7 +390,7 @@ unsafe extern "C" fn content_security_policy_allows(
RuntimeCode::WASM => csp_list.is_wasm_evaluation_allowed(),
};
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
allowed = is_evaluation_allowed == CheckResult::Allowed;
});
allowed
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 54cf89a213f..d6ab18be49b 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -3606,7 +3606,8 @@ impl ScriptThread {
fn handle_csp_violations(&self, id: PipelineId, _: RequestId, violations: Vec<csp::Violation>) {
if let Some(global) = self.documents.borrow().find_global(id) {
- global.report_csp_violations(violations);
+ // TODO(https://github.com/w3c/webappsec-csp/issues/687): Update after spec is resolved
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/security_manager.rs b/components/script/security_manager.rs
index ee320206de2..ee062594eb8 100644
--- a/components/script/security_manager.rs
+++ b/components/script/security_manager.rs
@@ -14,8 +14,7 @@ use crate::dom::bindings::codegen::Bindings::SecurityPolicyViolationEventBinding
};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
-use crate::dom::bindings::reflector::DomGlobal;
-use crate::dom::event::{Event, EventBubbles, EventCancelable};
+use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
use crate::dom::eventtarget::EventTarget;
use crate::dom::securitypolicyviolationevent::SecurityPolicyViolationEvent;
use crate::dom::types::GlobalScope;
@@ -23,6 +22,7 @@ use crate::script_runtime::CanGc;
use crate::task::TaskOnce;
pub(crate) struct CSPViolationReportTask {
+ global: Trusted<GlobalScope>,
event_target: Trusted<EventTarget>,
violation_report: SecurityPolicyViolationReport,
}
@@ -159,28 +159,31 @@ impl CSPViolationReportBuilder {
impl CSPViolationReportTask {
pub fn new(
- global: &GlobalScope,
- report: SecurityPolicyViolationReport,
+ global: Trusted<GlobalScope>,
+ event_target: Trusted<EventTarget>,
+ violation_report: SecurityPolicyViolationReport,
) -> CSPViolationReportTask {
CSPViolationReportTask {
- violation_report: report,
- event_target: Trusted::new(global.upcast::<EventTarget>()),
+ global,
+ event_target,
+ violation_report,
}
}
fn fire_violation_event(self, can_gc: CanGc) {
- let target = self.event_target.root();
- let global = &target.global();
let event = SecurityPolicyViolationEvent::new(
- global,
+ &self.global.root(),
Atom::from("securitypolicyviolation"),
EventBubbles::Bubbles,
EventCancelable::Cancelable,
+ EventComposed::Composed,
&self.violation_report.convert(),
can_gc,
);
- event.upcast::<Event>().fire(&target, can_gc);
+ event
+ .upcast::<Event>()
+ .fire(&self.event_target.root(), can_gc);
}
}
diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs
index 67e186c7f6a..a18d63e323b 100644
--- a/components/script/stylesheet_loader.rs
+++ b/components/script/stylesheet_loader.rs
@@ -286,7 +286,7 @@ impl FetchResponseListener for StylesheetContext {
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
let global = &self.resource_timing_global();
- global.report_csp_violations(violations);
+ global.report_csp_violations(violations, None);
}
}
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 781ac53f415..330ae4f0788 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -53,6 +53,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{DomGlobal, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
+use crate::dom::document::Document;
use crate::dom::element::Element;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
@@ -77,12 +78,27 @@ fn find_node_by_unique_id(
pipeline: PipelineId,
node_id: String,
) -> Result<DomRoot<Node>, ErrorStatus> {
- match documents.find_document(pipeline).and_then(|document| {
- document
- .upcast::<Node>()
- .traverse_preorder(ShadowIncluding::Yes)
- .find(|node| node.unique_id() == node_id)
- }) {
+ match documents.find_document(pipeline) {
+ Some(doc) => find_node_by_unique_id_in_document(&doc, node_id),
+ None => {
+ if ScriptThread::has_node_id(&node_id) {
+ Err(ErrorStatus::StaleElementReference)
+ } else {
+ Err(ErrorStatus::NoSuchElement)
+ }
+ },
+ }
+}
+
+pub(crate) fn find_node_by_unique_id_in_document(
+ document: &Document,
+ node_id: String,
+) -> Result<DomRoot<Node>, ErrorStatus> {
+ match document
+ .upcast::<Node>()
+ .traverse_preorder(ShadowIncluding::Yes)
+ .find(|node| node.unique_id() == node_id)
+ {
Some(node) => Ok(node),
None => {
if ScriptThread::has_node_id(&node_id) {
@@ -183,7 +199,7 @@ unsafe fn is_arguments_object(cx: *mut JSContext, value: HandleValue) -> bool {
jsstring_to_str(cx, class_name) == "[object Arguments]"
}
-#[derive(Eq, Hash, PartialEq)]
+#[derive(Clone, Eq, Hash, PartialEq)]
struct HashableJSVal(u64);
impl From<HandleValue<'_>> for HashableJSVal {
@@ -193,6 +209,7 @@ impl From<HandleValue<'_>> for HashableJSVal {
}
#[allow(unsafe_code)]
+/// <https://w3c.github.io/webdriver/#dfn-json-deserialize>
pub(crate) fn jsval_to_webdriver(
cx: SafeJSContext,
global_scope: &GlobalScope,
@@ -215,12 +232,6 @@ unsafe fn jsval_to_webdriver_inner(
val: HandleValue,
seen: &mut HashSet<HashableJSVal>,
) -> WebDriverJSResult {
- let hashable = val.into();
- if seen.contains(&hashable) {
- return Err(WebDriverJSError::JSError);
- }
- seen.insert(hashable);
-
let _ac = enter_realm(global_scope);
if val.get().is_undefined() {
Ok(WebDriverJSValue::Undefined)
@@ -252,14 +263,26 @@ unsafe fn jsval_to_webdriver_inner(
_ => unreachable!(),
};
Ok(WebDriverJSValue::String(String::from(string)))
- } else if val.get().is_object() {
+ }
+ // https://w3c.github.io/webdriver/#dfn-clone-an-object
+ else if val.get().is_object() {
+ let hashable = val.into();
+ // Step 1. If value is in `seen`, return error with error code javascript error.
+ if seen.contains(&hashable) {
+ return Err(WebDriverJSError::JSError);
+ }
+ //Step 2. Append value to `seen`.
+ seen.insert(hashable.clone());
+
rooted!(in(cx) let object = match FromJSValConvertible::from_jsval(cx, val, ()).unwrap() {
ConversionResult::Success(object) => object,
_ => unreachable!(),
});
let _ac = JSAutoRealm::new(cx, *object);
- if is_array_like::<crate::DomTypeHolder>(cx, val) || is_arguments_object(cx, val) {
+ let return_val = if is_array_like::<crate::DomTypeHolder>(cx, val) ||
+ is_arguments_object(cx, val)
+ {
let mut result: Vec<WebDriverJSValue> = Vec::new();
let length = match get_property::<u32>(
@@ -282,7 +305,7 @@ unsafe fn jsval_to_webdriver_inner(
return Err(WebDriverJSError::JSError);
},
};
-
+ // Step 4. For each enumerable property in value, run the following substeps:
for i in 0..length {
rooted!(in(cx) let mut item = UndefinedValue());
match get_property_jsval(cx, object.handle(), &i.to_string(), item.handle_mut()) {
@@ -303,7 +326,6 @@ unsafe fn jsval_to_webdriver_inner(
},
}
}
-
Ok(WebDriverJSValue::ArrayLike(result))
} else if let Ok(element) = root_from_object::<Element>(*object, cx) {
Ok(WebDriverJSValue::Element(WebElement(
@@ -312,7 +334,7 @@ unsafe fn jsval_to_webdriver_inner(
} else if let Ok(window) = root_from_object::<Window>(*object, cx) {
let window_proxy = window.window_proxy();
if window_proxy.is_browsing_context_discarded() {
- Err(WebDriverJSError::StaleElementReference)
+ return Err(WebDriverJSError::StaleElementReference);
} else if window_proxy.browsing_context_id() == window_proxy.webview_id() {
Ok(WebDriverJSValue::Window(WebWindow(
window.Document().upcast::<Node>().unique_id(),
@@ -332,7 +354,12 @@ unsafe fn jsval_to_webdriver_inner(
&HandleValueArray::empty(),
value.handle_mut(),
) {
- jsval_to_webdriver_inner(cx, global_scope, value.handle(), seen)
+ Ok(jsval_to_webdriver_inner(
+ cx,
+ global_scope,
+ value.handle(),
+ seen,
+ )?)
} else {
throw_dom_exception(
SafeJSContext::from_ptr(cx),
@@ -340,7 +367,7 @@ unsafe fn jsval_to_webdriver_inner(
Error::JSFailed,
CanGc::note(),
);
- Err(WebDriverJSError::JSError)
+ return Err(WebDriverJSError::JSError);
}
} else {
let mut result = HashMap::new();
@@ -392,9 +419,12 @@ unsafe fn jsval_to_webdriver_inner(
}
}
}
-
Ok(WebDriverJSValue::Object(result))
- }
+ };
+ // Step 5. Remove the last element of `seen`.
+ seen.remove(&hashable);
+ // Step 6. Return success with data `result`.
+ return_val
} else {
Err(WebDriverJSError::UnknownType)
}
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index cb33188804f..2a9874a386f 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -88,7 +88,7 @@ DOMInterfaces = {
},
'Clipboard': {
- 'canGc': ['WriteText']
+ 'canGc': ['ReadText', 'WriteText']
},
'ClipboardItem': {
diff --git a/components/script_bindings/conversions.rs b/components/script_bindings/conversions.rs
index 4d8e7aa595c..953dca889a8 100644
--- a/components/script_bindings/conversions.rs
+++ b/components/script_bindings/conversions.rs
@@ -532,7 +532,7 @@ where
/// Returns whether `value` is an array-like object (Array, FileList,
/// HTMLCollection, HTMLFormControlsCollection, HTMLOptionsCollection,
-/// NodeList).
+/// NodeList, DOMTokenList).
///
/// # Safety
/// `cx` must point to a valid, non-null JSContext.
@@ -548,6 +548,10 @@ pub unsafe fn is_array_like<D: crate::DomTypes>(cx: *mut JSContext, value: Handl
_ => return false,
};
+ // TODO: HTMLAllCollection
+ if root_from_object::<D::DOMTokenList>(object, cx).is_ok() {
+ return true;
+ }
if root_from_object::<D::FileList>(object, cx).is_ok() {
return true;
}
diff --git a/components/script_bindings/webidls/Clipboard.webidl b/components/script_bindings/webidls/Clipboard.webidl
index 7562adbfa38..b77e975917e 100644
--- a/components/script_bindings/webidls/Clipboard.webidl
+++ b/components/script_bindings/webidls/Clipboard.webidl
@@ -9,7 +9,7 @@ typedef sequence<ClipboardItem> ClipboardItems;
[SecureContext, Exposed=Window, Pref="dom_async_clipboard_enabled"]
interface Clipboard : EventTarget {
// Promise<ClipboardItems> read();
- // Promise<DOMString> readText();
+ Promise<DOMString> readText();
// Promise<undefined> write(ClipboardItems data);
Promise<undefined> writeText(DOMString data);
};
diff --git a/components/script_bindings/webidls/TransformStream.webidl b/components/script_bindings/webidls/TransformStream.webidl
new file mode 100644
index 00000000000..c36a49b114a
--- /dev/null
+++ b/components/script_bindings/webidls/TransformStream.webidl
@@ -0,0 +1,18 @@
+/* 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 http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://streams.spec.whatwg.org/#ts-class-definition
+ */
+
+[Exposed=*] // [Transferable] - See Bug 1562065
+interface TransformStream {
+ [Throws]
+ constructor(optional object transformer,
+ optional QueuingStrategy writableStrategy = {},
+ optional QueuingStrategy readableStrategy = {});
+
+ readonly attribute ReadableStream readable;
+ readonly attribute WritableStream writable;
+};
diff --git a/components/script_bindings/webidls/TransformStreamDefaultController.webidl b/components/script_bindings/webidls/TransformStreamDefaultController.webidl
new file mode 100644
index 00000000000..5f5511ed4b6
--- /dev/null
+++ b/components/script_bindings/webidls/TransformStreamDefaultController.webidl
@@ -0,0 +1,15 @@
+/* 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 http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://streams.spec.whatwg.org/#ts-default-controller-class-definition
+ */
+
+[Exposed=*]
+interface TransformStreamDefaultController {
+ readonly attribute unrestricted double? desiredSize;
+ [Throws] undefined enqueue(optional any chunk);
+ [Throws] undefined error(optional any reason);
+ [Throws] undefined terminate();
+};
diff --git a/components/script_bindings/webidls/Transformer.webidl b/components/script_bindings/webidls/Transformer.webidl
new file mode 100644
index 00000000000..652511450a4
--- /dev/null
+++ b/components/script_bindings/webidls/Transformer.webidl
@@ -0,0 +1,22 @@
+/* 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 http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://streams.spec.whatwg.org/#transformer-api
+ */
+
+[GenerateInit]
+dictionary Transformer {
+ TransformerStartCallback start;
+ TransformerTransformCallback transform;
+ TransformerFlushCallback flush;
+ TransformerCancelCallback cancel;
+ any readableType;
+ any writableType;
+};
+
+callback TransformerStartCallback = any (TransformStreamDefaultController controller);
+callback TransformerFlushCallback = Promise<undefined> (TransformStreamDefaultController controller);
+callback TransformerTransformCallback = Promise<undefined> (any chunk, TransformStreamDefaultController controller);
+callback TransformerCancelCallback = Promise<undefined> (any reason);
diff --git a/components/script_bindings/webidls/Window.webidl b/components/script_bindings/webidls/Window.webidl
index eb7c3e1d03d..929279f7951 100644
--- a/components/script_bindings/webidls/Window.webidl
+++ b/components/script_bindings/webidls/Window.webidl
@@ -150,6 +150,10 @@ partial interface Window {
undefined webdriverCallback(optional any result);
undefined webdriverException(optional any result);
undefined webdriverTimeout();
+ Element? webdriverElement(DOMString id);
+ Element? webdriverFrame(DOMString id);
+ Window? webdriverWindow(DOMString id);
+ ShadowRoot? webdriverShadowRoot(DOMString id);
};
// https://html.spec.whatwg.org/multipage/#dom-sessionstorage
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 366685e1123..b8210450cd8 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -1044,7 +1044,11 @@ fn create_constellation(
);
let system_font_service = Arc::new(
- SystemFontService::spawn(compositor_proxy.cross_process_compositor_api.clone()).to_proxy(),
+ SystemFontService::spawn(
+ compositor_proxy.cross_process_compositor_api.clone(),
+ mem_profiler_chan.clone(),
+ )
+ .to_proxy(),
);
let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start(
diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs
index 31371f87529..a6701ca2b52 100644
--- a/components/shared/compositing/lib.rs
+++ b/components/shared/compositing/lib.rs
@@ -14,6 +14,7 @@ use embedder_traits::{
use euclid::Rect;
use ipc_channel::ipc::IpcSender;
use log::warn;
+use malloc_size_of_derive::MallocSizeOf;
use pixels::Image;
use strum_macros::IntoStaticStr;
use style_traits::CSSPixel;
@@ -103,6 +104,8 @@ pub enum CompositorMsg {
WebDriverMouseButtonEvent(WebViewId, MouseButtonAction, MouseButton, f32, f32),
/// WebDriver mouse move event
WebDriverMouseMoveEvent(WebViewId, f32, f32),
+ // Webdriver wheel scroll event
+ WebDriverWheelScrollEvent(WebViewId, f32, f32, f64, f64),
/// Inform WebRender of the existence of this pipeline.
SendInitialTransaction(WebRenderPipelineId),
@@ -188,7 +191,7 @@ pub struct CompositionPipeline {
}
/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
-#[derive(Clone, Deserialize, Serialize)]
+#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub struct CrossProcessCompositorApi(pub IpcSender<CompositorMsg>);
impl CrossProcessCompositorApi {
diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs
index 0268be6dd9c..acaa9afb3ff 100644
--- a/components/shared/embedder/input_events.rs
+++ b/components/shared/embedder/input_events.rs
@@ -61,15 +61,16 @@ pub enum MouseButton {
Other(u16),
}
-impl From<u16> for MouseButton {
- fn from(value: u16) -> Self {
+impl<T: Into<u64>> From<T> for MouseButton {
+ fn from(value: T) -> Self {
+ let value = value.into();
match value {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
3 => MouseButton::Back,
4 => MouseButton::Forward,
- _ => MouseButton::Other(value),
+ _ => MouseButton::Other(value as u16),
}
}
}
diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs
index 9577163411e..3716a29951a 100644
--- a/components/shared/embedder/webdriver.rs
+++ b/components/shared/embedder/webdriver.rs
@@ -44,6 +44,8 @@ pub enum WebDriverCommandMsg {
MouseButtonAction(WebViewId, MouseButtonAction, MouseButton, f32, f32),
/// Act as if the mouse was moved in the browsing context with the given ID.
MouseMoveAction(WebViewId, f32, f32),
+ /// Act as if the mouse wheel is scrolled in the browsing context given the given ID.
+ WheelScrollAction(WebViewId, f32, f32, f64, f64),
/// Set the window size.
SetWindowSize(WebViewId, DeviceIntSize, IpcSender<Size2D<f32, CSSPixel>>),
/// Take a screenshot of the window.
diff --git a/components/shared/profile/mem.rs b/components/shared/profile/mem.rs
index 1be4eb5abc4..b626facd042 100644
--- a/components/shared/profile/mem.rs
+++ b/components/shared/profile/mem.rs
@@ -279,7 +279,6 @@ thread_local!(static SEEN_POINTERS: LazyCell<RefCell<HashSet<*const c_void>>> =
/// The function is expected to call all the desired [MallocSizeOf::size_of]
/// for allocations reachable from the current thread.
pub fn perform_memory_report<F: FnOnce(&mut MallocSizeOfOps)>(f: F) {
- SEEN_POINTERS.with(|pointers| pointers.borrow_mut().clear());
let seen_pointer = move |ptr| SEEN_POINTERS.with(|pointers| !pointers.borrow_mut().insert(ptr));
let mut ops = MallocSizeOfOps::new(
servo_allocator::usable_size,
@@ -287,4 +286,9 @@ pub fn perform_memory_report<F: FnOnce(&mut MallocSizeOfOps)>(f: F) {
Some(Box::new(seen_pointer)),
);
f(&mut ops);
+ SEEN_POINTERS.with(|pointers| {
+ let mut pointers = pointers.borrow_mut();
+ pointers.clear();
+ pointers.shrink_to_fit();
+ });
}
diff --git a/components/url/lib.rs b/components/url/lib.rs
index 8aa04fd5ae4..f1ae1083c8e 100644
--- a/components/url/lib.rs
+++ b/components/url/lib.rs
@@ -35,7 +35,7 @@ pub enum UrlError {
}
#[derive(Clone, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
-pub struct ServoUrl(#[ignore_malloc_size_of = "Arc"] Arc<Url>);
+pub struct ServoUrl(#[conditional_malloc_size_of] Arc<Url>);
impl ServoUrl {
pub fn from_url(url: Url) -> Self {
diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs
index fbede5b5887..b18a6eaaf2e 100644
--- a/components/webdriver_server/actions.rs
+++ b/components/webdriver_server/actions.rs
@@ -13,20 +13,23 @@ use keyboard_types::webdriver::KeyInputState;
use webdriver::actions::{
ActionSequence, ActionsType, GeneralAction, KeyAction, KeyActionItem, KeyDownAction,
KeyUpAction, NullActionItem, PointerAction, PointerActionItem, PointerActionParameters,
- PointerDownAction, PointerMoveAction, PointerOrigin, PointerType, PointerUpAction,
+ PointerDownAction, PointerMoveAction, PointerOrigin, PointerType, PointerUpAction, WheelAction,
+ WheelActionItem, WheelScrollAction,
};
use webdriver::error::ErrorStatus;
use crate::Handler;
-// Interval between pointerMove increments in ms, based on common vsync
+// Interval between wheelScroll and pointerMove increments in ms, based on common vsync
static POINTERMOVE_INTERVAL: u64 = 17;
+static WHEELSCROLL_INTERVAL: u64 = 17;
// https://w3c.github.io/webdriver/#dfn-input-source-state
pub(crate) enum InputSourceState {
Null,
Key(KeyInputState),
Pointer(PointerInputState),
+ Wheel,
}
// https://w3c.github.io/webdriver/#dfn-pointer-input-source
@@ -76,7 +79,15 @@ fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 {
}
},
ActionsType::Key { actions: _ } => (),
- ActionsType::Wheel { .. } => log::error!("not implemented"),
+ ActionsType::Wheel { actions } => {
+ for action in actions.iter() {
+ let action_duration = match action {
+ WheelActionItem::General(GeneralAction::Pause(action)) => action.duration,
+ WheelActionItem::Wheel(WheelAction::Scroll(action)) => action.duration,
+ };
+ duration = cmp::max(duration, action_duration.unwrap_or(0));
+ }
+ },
}
duration
}
@@ -176,9 +187,26 @@ impl Handler {
}
}
},
- ActionsType::Wheel { .. } => {
- log::error!("not yet implemented");
- return Err(ErrorStatus::UnsupportedOperation);
+ ActionsType::Wheel { actions } => {
+ for action in actions.iter() {
+ match action {
+ WheelActionItem::General(_action) => {
+ self.dispatch_general_action(source_id)
+ },
+ WheelActionItem::Wheel(action) => {
+ self.session_mut()
+ .unwrap()
+ .input_state_table
+ .entry(source_id.to_string())
+ .or_insert(InputSourceState::Wheel);
+ match action {
+ WheelAction::Scroll(action) => {
+ self.dispatch_scroll_action(action, tick_duration)?
+ },
+ }
+ },
+ }
+ }
},
}
@@ -191,9 +219,8 @@ impl Handler {
let raw_key = action.value.chars().next().unwrap();
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
- InputSourceState::Null => unreachable!(),
InputSourceState::Key(key_input_state) => key_input_state,
- InputSourceState::Pointer(_) => unreachable!(),
+ _ => unreachable!(),
};
session.input_cancel_list.push(ActionSequence {
@@ -219,9 +246,8 @@ impl Handler {
let raw_key = action.value.chars().next().unwrap();
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
- InputSourceState::Null => unreachable!(),
InputSourceState::Key(key_input_state) => key_input_state,
- InputSourceState::Pointer(_) => unreachable!(),
+ _ => unreachable!(),
};
session.input_cancel_list.push(ActionSequence {
@@ -251,9 +277,8 @@ impl Handler {
let session = self.session.as_mut().unwrap();
let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
- InputSourceState::Null => unreachable!(),
- InputSourceState::Key(_) => unreachable!(),
InputSourceState::Pointer(pointer_input_state) => pointer_input_state,
+ _ => unreachable!(),
};
if pointer_input_state.pressed.contains(&action.button) {
@@ -280,11 +305,10 @@ impl Handler {
},
});
- let button = (action.button as u16).into();
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
session.webview_id,
MouseButtonAction::Down,
- button,
+ action.button.into(),
pointer_input_state.x as f32,
pointer_input_state.y as f32,
);
@@ -298,9 +322,8 @@ impl Handler {
let session = self.session.as_mut().unwrap();
let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
- InputSourceState::Null => unreachable!(),
- InputSourceState::Key(_) => unreachable!(),
InputSourceState::Pointer(pointer_input_state) => pointer_input_state,
+ _ => unreachable!(),
};
if !pointer_input_state.pressed.contains(&action.button) {
@@ -327,11 +350,10 @@ impl Handler {
},
});
- let button = (action.button as u16).into();
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
session.webview_id,
MouseButtonAction::Up,
- button,
+ action.button.into(),
pointer_input_state.x as f32,
pointer_input_state.y as f32,
);
@@ -362,14 +384,12 @@ impl Handler {
.get(source_id)
.unwrap()
{
- InputSourceState::Null => unreachable!(),
- InputSourceState::Key(_) => unreachable!(),
InputSourceState::Pointer(pointer_input_state) => {
(pointer_input_state.x, pointer_input_state.y)
},
+ _ => unreachable!(),
};
- // Step 5 - 6
let (x, y) = match action.origin {
PointerOrigin::Viewport => (x_offset, y_offset),
PointerOrigin::Pointer => (start_x + x_offset, start_y + y_offset),
@@ -387,18 +407,8 @@ impl Handler {
},
};
- let (sender, receiver) = ipc::channel().unwrap();
- let cmd_msg =
- WebDriverCommandMsg::GetWindowSize(self.session.as_ref().unwrap().webview_id, sender);
- self.constellation_chan
- .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
- .unwrap();
-
- // Steps 7 - 8
- let viewport_size = receiver.recv().unwrap();
- if x < 0 || x as f32 > viewport_size.width || y < 0 || y as f32 > viewport_size.height {
- return Err(ErrorStatus::MoveTargetOutOfBounds);
- }
+ // Step 5 - 6
+ self.check_viewport_bound(x, y)?;
// Step 9
let duration = match action.duration {
@@ -432,9 +442,8 @@ impl Handler {
) {
let session = self.session.as_mut().unwrap();
let pointer_input_state = match session.input_state_table.get_mut(source_id).unwrap() {
- InputSourceState::Null => unreachable!(),
- InputSourceState::Key(_) => unreachable!(),
InputSourceState::Pointer(pointer_input_state) => pointer_input_state,
+ _ => unreachable!(),
};
loop {
@@ -487,4 +496,168 @@ impl Handler {
thread::sleep(Duration::from_millis(POINTERMOVE_INTERVAL));
}
}
+
+ /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-scroll-action>
+ fn dispatch_scroll_action(
+ &mut self,
+ action: &WheelScrollAction,
+ tick_duration: u64,
+ ) -> Result<(), ErrorStatus> {
+ // Note: We have not implemented `extract an action sequence` which will calls
+ // `process a wheel action` that validate many of the variable used here.
+ // Hence, we do all the checking here until those functions is properly
+ // implemented.
+ // <https://w3c.github.io/webdriver/#dfn-process-a-wheel-action>
+
+ let tick_start = Instant::now();
+
+ // Step 1
+ let Some(x_offset) = action.x else {
+ return Err(ErrorStatus::InvalidArgument);
+ };
+
+ // Step 2
+ let Some(y_offset) = action.y else {
+ return Err(ErrorStatus::InvalidArgument);
+ };
+
+ // Step 3 - 4
+ // Get coordinates relative to an origin. Origin must be viewport.
+ let (x, y) = match action.origin {
+ PointerOrigin::Viewport => (x_offset, y_offset),
+ _ => return Err(ErrorStatus::InvalidArgument),
+ };
+
+ // Step 5 - 6
+ self.check_viewport_bound(x, y)?;
+
+ // Step 7 - 8
+ let Some(delta_x) = action.deltaX else {
+ return Err(ErrorStatus::InvalidArgument);
+ };
+
+ let Some(delta_y) = action.deltaY else {
+ return Err(ErrorStatus::InvalidArgument);
+ };
+
+ // Step 9
+ let duration = match action.duration {
+ Some(duration) => duration,
+ None => tick_duration,
+ };
+
+ // Step 10
+ if duration > 0 {
+ thread::sleep(Duration::from_millis(WHEELSCROLL_INTERVAL));
+ }
+
+ // Step 11
+ self.perform_scroll(duration, x, y, delta_x, delta_y, 0, 0, tick_start);
+
+ // Step 12
+ Ok(())
+ }
+
+ /// <https://w3c.github.io/webdriver/#dfn-perform-a-scroll>
+ #[allow(clippy::too_many_arguments)]
+ fn perform_scroll(
+ &mut self,
+ duration: u64,
+ x: i64,
+ y: i64,
+ target_delta_x: i64,
+ target_delta_y: i64,
+ mut curr_delta_x: i64,
+ mut curr_delta_y: i64,
+ tick_start: Instant,
+ ) {
+ let session = self.session.as_mut().unwrap();
+
+ // Step 1
+ let time_delta = tick_start.elapsed().as_millis();
+
+ // Step 2
+ let duration_ratio = if duration > 0 {
+ time_delta as f64 / duration as f64
+ } else {
+ 1.0
+ };
+
+ // Step 3
+ let last = 1.0 - duration_ratio < 0.001;
+
+ // Step 4
+ let (delta_x, delta_y) = if last {
+ (target_delta_x - curr_delta_x, target_delta_y - curr_delta_y)
+ } else {
+ (
+ (duration_ratio * target_delta_x as f64) as i64 - curr_delta_x,
+ (duration_ratio * target_delta_y as f64) as i64 - curr_delta_y,
+ )
+ };
+
+ // Step 5
+ if delta_x != 0 || delta_y != 0 {
+ // Perform implementation-specific action dispatch steps
+ let cmd_msg = WebDriverCommandMsg::WheelScrollAction(
+ session.webview_id,
+ x as f32,
+ y as f32,
+ delta_x as f64,
+ delta_y as f64,
+ );
+ self.constellation_chan
+ .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
+ .unwrap();
+
+ curr_delta_x += delta_x;
+ curr_delta_y += delta_y;
+ }
+
+ // Step 6
+ if last {
+ return;
+ }
+
+ // Step 7
+ // TODO: The two steps should be done in parallel
+ // 7.1. Asynchronously wait for an implementation defined amount of time to pass.
+ thread::sleep(Duration::from_millis(WHEELSCROLL_INTERVAL));
+ // 7.2. Perform a scroll with arguments duration, x, y, target delta x,
+ // target delta y, current delta x, current delta y.
+ self.perform_scroll(
+ duration,
+ x,
+ y,
+ target_delta_x,
+ target_delta_y,
+ curr_delta_x,
+ curr_delta_y,
+ tick_start,
+ );
+ }
+
+ fn check_viewport_bound(&self, x: i64, y: i64) -> Result<(), ErrorStatus> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ let cmd_msg =
+ WebDriverCommandMsg::GetWindowSize(self.session.as_ref().unwrap().webview_id, sender);
+ self.constellation_chan
+ .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
+ .unwrap();
+
+ match receiver.recv() {
+ Ok(viewport_size) => {
+ if x < 0 ||
+ x as f32 > viewport_size.width ||
+ y < 0 ||
+ y as f32 > viewport_size.height
+ {
+ Err(ErrorStatus::MoveTargetOutOfBounds)
+ } else {
+ Ok(())
+ }
+ },
+ Err(_) => Err(ErrorStatus::UnknownError),
+ }
+ }
}
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index d003ebf8adb..ad5b4e736a9 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -23,7 +23,7 @@ use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use cookie::{CookieBuilder, Expiration};
use crossbeam_channel::{Receiver, Sender, after, select, unbounded};
use embedder_traits::{
- WebDriverCommandMsg, WebDriverCookieError, WebDriverFrameId, WebDriverJSError,
+ MouseButton, WebDriverCommandMsg, WebDriverCookieError, WebDriverFrameId, WebDriverJSError,
WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverScriptCommand,
};
use euclid::{Rect, Size2D};
@@ -1619,7 +1619,10 @@ impl Handler {
InputSourceState::Pointer(PointerInputState::new(&PointerType::Mouse)),
);
- // Steps 8.3 - 8.6
+ // Step 8.7. Construct a pointer move action.
+ // Step 8.8. Set a property x to 0 on pointer move action.
+ // Step 8.9. Set a property y to 0 on pointer move action.
+ // Step 8.10. Set a property origin to element on pointer move action.
let pointer_move_action = PointerMoveAction {
duration: None,
origin: PointerOrigin::Element(WebElement(element_id)),
@@ -1628,32 +1631,32 @@ impl Handler {
..Default::default()
};
- // Steps 8.7 - 8.8
+ // Step 8.11. Construct pointer down action.
+ // Step 8.12. Set a property button to 0 on pointer down action.
let pointer_down_action = PointerDownAction {
- button: 1,
+ button: i16::from(MouseButton::Left) as u64,
..Default::default()
};
- // Steps 8.9 - 8.10
+ // Step 8.13. Construct pointer up action.
+ // Step 8.14. Set a property button to 0 on pointer up action.
let pointer_up_action = PointerUpAction {
- button: 1,
+ button: i16::from(MouseButton::Left) as u64,
..Default::default()
};
- // Step 8.11
+ // Step 8.16 Dispatch a list of actions with input state,
+ // actions, session's current browsing context, and actions options.
if let Err(error) =
self.dispatch_pointermove_action(&id, &pointer_move_action, 0)
{
return Err(WebDriverError::new(error, ""));
}
- // Steps 8.12
self.dispatch_pointerdown_action(&id, &pointer_down_action);
-
- // Steps 8.13
self.dispatch_pointerup_action(&id, &pointer_up_action);
- // Step 8.14
+ // Step 8.17 Remove an input source with input state and input id.
self.session_mut()?.input_state_table.remove(&id);
// Step 13
@@ -1915,6 +1918,15 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
}
}
+/// <https://w3c.github.io/webdriver/#dfn-web-element-identifier>
+const ELEMENT_IDENTIFIER: &str = "element-6066-11e4-a52e-4f735466cecf";
+/// <https://w3c.github.io/webdriver/#dfn-web-frame-identifier>
+const FRAME_IDENTIFIER: &str = "frame-075b-4da1-b6ba-e579c2d3230a";
+/// <https://w3c.github.io/webdriver/#dfn-web-window-identifier>
+const WINDOW_IDENTIFIER: &str = "window-fcc6-11e5-b4f8-330a88ab9d7f";
+/// <https://w3c.github.io/webdriver/#dfn-shadow-root-identifier>
+const SHADOW_ROOT_IDENTIFIER: &str = "shadow-6066-11e4-a52e-4f735466cecf";
+
fn webdriver_value_to_js_argument(v: &Value) -> String {
match v {
Value::String(s) => format!("\"{}\"", s),
@@ -1929,6 +1941,22 @@ fn webdriver_value_to_js_argument(v: &Value) -> String {
format!("[{}]", elems.join(", "))
},
Value::Object(map) => {
+ let key = map.keys().next().map(String::as_str);
+ match (key, map.values().next()) {
+ (Some(ELEMENT_IDENTIFIER), Some(id)) => {
+ return format!("window.webdriverElement({})", id);
+ },
+ (Some(FRAME_IDENTIFIER), Some(id)) => {
+ return format!("window.webdriverFrame({})", id);
+ },
+ (Some(WINDOW_IDENTIFIER), Some(id)) => {
+ return format!("window.webdriverWindow({})", id);
+ },
+ (Some(SHADOW_ROOT_IDENTIFIER), Some(id)) => {
+ return format!("window.webdriverShadowRoot({})", id);
+ },
+ _ => {},
+ }
let elems = map
.iter()
.map(|(k, v)| format!("{}: {}", k, webdriver_value_to_js_argument(v)))
diff --git a/components/webgl/Cargo.toml b/components/webgl/Cargo.toml
index b0c1c0ceb29..542a3cb4fae 100644
--- a/components/webgl/Cargo.toml
+++ b/components/webgl/Cargo.toml
@@ -26,6 +26,7 @@ fnv = { workspace = true }
glow = { workspace = true }
half = "2"
ipc-channel = { workspace = true }
+itertools = { workspace = true }
log = { workspace = true }
pixels = { path = "../pixels" }
snapshot = { workspace = true }
diff --git a/components/webgl/webgl_thread.rs b/components/webgl/webgl_thread.rs
index b1ac2b2d3c4..9562c4cb4e0 100644
--- a/components/webgl/webgl_thread.rs
+++ b/components/webgl/webgl_thread.rs
@@ -32,6 +32,7 @@ use glow::{
};
use half::f16;
use ipc_channel::ipc::IpcSharedMemory;
+use itertools::Itertools;
use log::{debug, error, trace, warn};
use pixels::{self, PixelFormat, unmultiply_inplace};
use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI};
@@ -2570,24 +2571,10 @@ impl WebGLImpl {
chan.send((range_min, range_max, precision)).unwrap();
}
- fn get_extensions(gl: &Gl, chan: &WebGLSender<String>) {
- let mut ext_count = [0];
- unsafe {
- gl.get_parameter_i32_slice(gl::NUM_EXTENSIONS, &mut ext_count);
- }
- // Fall back to the depricated extensions API if that fails
- if unsafe { gl.get_error() } != gl::NO_ERROR {
- chan.send(unsafe { gl.get_parameter_string(gl::EXTENSIONS) })
- .unwrap();
- return;
- }
- let ext_count = ext_count[0] as usize;
- let mut extensions = Vec::with_capacity(ext_count);
- for idx in 0..ext_count {
- extensions.push(unsafe { gl.get_parameter_indexed_string(gl::EXTENSIONS, idx as u32) })
- }
- let extensions = extensions.join(" ");
- chan.send(extensions).unwrap();
+ /// This is an implementation of `getSupportedExtensions()` from
+ /// <https://registry.khronos.org/webgl/specs/latest/1.0/#5.14>
+ fn get_extensions(gl: &Gl, result_sender: &WebGLSender<String>) {
+ let _ = result_sender.send(gl.supported_extensions().iter().join(" "));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
diff --git a/python/requirements.txt b/python/requirements.txt
index 20d42065dde..d026ce3ee5f 100644
--- a/python/requirements.txt
+++ b/python/requirements.txt
@@ -37,3 +37,6 @@ types-requests
# For mach package on macOS.
Mako == 1.2.2
+
+# For devtools tests.
+geckordp == 1.0.3
diff --git a/python/servo/devtools_tests.py b/python/servo/devtools_tests.py
new file mode 100644
index 00000000000..c50fffb0ac1
--- /dev/null
+++ b/python/servo/devtools_tests.py
@@ -0,0 +1,150 @@
+# Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+from concurrent.futures import Future
+import logging
+from geckordp.actors.root import RootActor
+from geckordp.actors.descriptors.tab import TabActor
+from geckordp.actors.watcher import WatcherActor
+from geckordp.actors.resources import Resources
+from geckordp.actors.events import Events
+from geckordp.rdp_client import RDPClient
+import http.server
+import os.path
+import socketserver
+import subprocess
+import time
+from threading import Thread
+from typing import Optional
+import unittest
+
+
+class DevtoolsTests(unittest.IsolatedAsyncioTestCase):
+ # /path/to/servo/python/servo
+ script_path = None
+
+ def __init__(self, methodName="runTest"):
+ super().__init__(methodName)
+ self.servoshell = None
+ self.base_url = None
+ self.web_server = None
+ self.web_server_thread = None
+
+ def test_sources_list(self):
+ self.run_servoshell(test_dir=os.path.join(DevtoolsTests.script_path, "devtools_tests/sources"))
+ self.assert_sources_list([f"{self.base_url}/classic.js", f"{self.base_url}/test.html", "https://servo.org/js/load-table.js"])
+
+ def test_sources_list_with_data_no_scripts(self):
+ self.run_servoshell(url="data:text/html,")
+ self.assert_sources_list([])
+
+ def test_sources_list_with_data_empty_inline_script(self):
+ self.run_servoshell(url="data:text/html,<script></script>")
+ self.assert_sources_list([])
+
+ def test_sources_list_with_data_inline_script(self):
+ self.run_servoshell(url="data:text/html,<script>;</script>")
+ self.assert_sources_list(["data:text/html,<script>;</script>"])
+
+ def run_servoshell(self, *, test_dir=None, url=None):
+ if test_dir is None:
+ test_dir = os.path.join(DevtoolsTests.script_path, "devtools_tests")
+ base_url = Future()
+
+ class Handler(http.server.SimpleHTTPRequestHandler):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, directory=test_dir, **kwargs)
+
+ def log_message(self, format, *args):
+ # Uncomment this to log requests.
+ # return super().log_message(format, *args)
+ pass
+
+ def server_thread():
+ self.web_server = socketserver.TCPServer(("0.0.0.0", 0), Handler)
+ base_url.set_result(f"http://127.0.0.1:{self.web_server.server_address[1]}")
+ self.web_server.serve_forever()
+
+ # Start a web server for the test.
+ self.web_server_thread = Thread(target=server_thread)
+ self.web_server_thread.start()
+ self.base_url = base_url.result(1)
+
+ # Change this setting if you want to debug Servo.
+ os.environ["RUST_LOG"] = "error,devtools=warn"
+
+ # Run servoshell.
+ if url is None:
+ url = f"{self.base_url}/test.html"
+ self.servoshell = subprocess.Popen(["target/release/servo", "--devtools=6080", url])
+
+ # FIXME: Don’t do this
+ time.sleep(1)
+
+ def tearDown(self):
+ # Terminate servoshell.
+ self.servoshell.terminate()
+
+ # Stop the web server.
+ self.web_server.shutdown()
+ self.web_server_thread.join()
+
+ def assert_sources_list(self, expected_urls):
+ client = RDPClient()
+ client.connect("127.0.0.1", 6080)
+ root = RootActor(client)
+ tabs = root.list_tabs()
+ tab_dict = tabs[0]
+ tab = TabActor(client, tab_dict["actor"])
+ watcher = tab.get_watcher()
+ watcher = WatcherActor(client, watcher["actor"])
+
+ target = Future()
+
+ def on_target(data):
+ if data["target"]["browsingContextID"] == tab_dict["browsingContextID"]:
+ target.set_result(data["target"])
+
+ client.add_event_listener(
+ watcher.actor_id, Events.Watcher.TARGET_AVAILABLE_FORM, on_target,
+ )
+ watcher.watch_targets(WatcherActor.Targets.FRAME)
+
+ done = Future()
+ target = target.result(1)
+
+ def on_source_resource(data):
+ for [resource_type, sources] in data["array"]:
+ try:
+ self.assertEqual(resource_type, "source")
+ self.assertEqual([source["url"] for source in sources], expected_urls)
+ done.set_result(None)
+ except Exception as e:
+ # Raising here does nothing, for some reason.
+ # Send the exception back so it can be raised.
+ done.set_result(e)
+
+ client.add_event_listener(
+ target["actor"],
+ Events.Watcher.RESOURCES_AVAILABLE_ARRAY,
+ on_source_resource,
+ )
+ watcher.watch_resources([Resources.SOURCE])
+
+ result: Optional[Exception] = done.result(1)
+ if result:
+ raise result
+ client.disconnect()
+
+
+def run_tests(script_path):
+ DevtoolsTests.script_path = script_path
+ verbosity = 1 if logging.getLogger().level >= logging.WARN else 2
+ suite = unittest.TestLoader().loadTestsFromTestCase(DevtoolsTests)
+ return unittest.TextTestRunner(verbosity=verbosity).run(suite).wasSuccessful()
diff --git a/python/servo/devtools_tests/sources/classic.js b/python/servo/devtools_tests/sources/classic.js
new file mode 100644
index 00000000000..84fd1671805
--- /dev/null
+++ b/python/servo/devtools_tests/sources/classic.js
@@ -0,0 +1 @@
+console.log("external classic");
diff --git a/python/servo/devtools_tests/sources/module.js b/python/servo/devtools_tests/sources/module.js
new file mode 100644
index 00000000000..a1d0f1f37cf
--- /dev/null
+++ b/python/servo/devtools_tests/sources/module.js
@@ -0,0 +1,2 @@
+export default 1;
+console.log("external module");
diff --git a/python/servo/devtools_tests/sources/test.html b/python/servo/devtools_tests/sources/test.html
new file mode 100644
index 00000000000..b8e1aa0e334
--- /dev/null
+++ b/python/servo/devtools_tests/sources/test.html
@@ -0,0 +1,11 @@
+<!doctype html><meta charset=utf-8>
+<script src="classic.js"></script>
+<script>
+ console.log("inline classic");
+ new Worker("worker.js");
+</script>
+<script type="module">
+ import module from "./module.js";
+ console.log("inline module");
+</script>
+<script src="https://servo.org/js/load-table.js"></script>
diff --git a/python/servo/devtools_tests/sources/worker.js b/python/servo/devtools_tests/sources/worker.js
new file mode 100644
index 00000000000..a7993a8b5fb
--- /dev/null
+++ b/python/servo/devtools_tests/sources/worker.js
@@ -0,0 +1 @@
+console.log("external classic worker");
diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py
index 860217d062a..5e5a8c2e8d2 100644
--- a/python/servo/testing_commands.py
+++ b/python/servo/testing_commands.py
@@ -19,6 +19,7 @@ import subprocess
import textwrap
import json
+import servo.devtools_tests
from servo.post_build_commands import PostBuildCommands
import wpt
import wpt.manifestupdate
@@ -326,6 +327,14 @@ class MachCommands(CommandBase):
return 0 if passed else 1
+ @Command('test-devtools',
+ description='Run tests for devtools.',
+ category='testing')
+ def test_devtools(self):
+ print("Running devtools tests...")
+ passed = servo.devtools_tests.run_tests(SCRIPT_PATH)
+ return 0 if passed else 1
+
@Command('test-wpt-failure',
description='Run the tests harness that verifies that the test failures are reported correctly',
category='testing',
diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini
index ba81ab64b83..8ea1e50b8d0 100644
--- a/tests/wpt/include.ini
+++ b/tests/wpt/include.ini
@@ -256,6 +256,8 @@ skip: true
skip: true
[writable-streams]
skip: false
+ [transform-streams]
+ skip: false
[subresource-integrity]
skip: false
[touch-events]
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index df2beac06bd..893b07e9e3f 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -569742,7 +569742,7 @@
]
],
"icon-blocked.sub.html": [
- "cc882347a1ac7b595275c2263ef266826e6f07bd",
+ "4c39e5dec735c10635a603356367610d3aad3fa2",
[
null,
{}
@@ -569797,6 +569797,13 @@
{}
]
],
+ "img-src-targeting.html": [
+ "3b4fe7c690b0b980a9626de0deb02c8950f5d4a0",
+ [
+ null,
+ {}
+ ]
+ ],
"img-src-wildcard-allowed.html": [
"050a4d14100bb1ef719d6700bfbd37a97424af59",
[
diff --git a/tests/wpt/meta/clipboard-apis/idlharness.https.window.js.ini b/tests/wpt/meta/clipboard-apis/idlharness.https.window.js.ini
index 98bb3d8b303..e648b62a314 100644
--- a/tests/wpt/meta/clipboard-apis/idlharness.https.window.js.ini
+++ b/tests/wpt/meta/clipboard-apis/idlharness.https.window.js.ini
@@ -8,9 +8,6 @@
[Clipboard interface: operation read(optional ClipboardUnsanitizedFormats)]
expected: FAIL
- [Clipboard interface: operation readText()]
- expected: FAIL
-
[Clipboard interface: operation write(ClipboardItems)]
expected: FAIL
@@ -20,9 +17,6 @@
[Clipboard interface: calling read(optional ClipboardUnsanitizedFormats) on navigator.clipboard with too few arguments must throw TypeError]
expected: FAIL
- [Clipboard interface: navigator.clipboard must inherit property "readText()" with the proper type]
- expected: FAIL
-
[Clipboard interface: navigator.clipboard must inherit property "write(ClipboardItems)" with the proper type]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.http.html.ini b/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.http.html.ini
index e29f4dd5d4e..5891a18681e 100644
--- a/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.http.html.ini
+++ b/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.http.html.ini
@@ -1,13 +1,4 @@
[script-tag.http.html]
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and keep-origin redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and no-redirect redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and swap-origin redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.https.html.ini b/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.https.html.ini
index bbe30519d0b..699a0dd6238 100644
--- a/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.https.html.ini
+++ b/tests/wpt/meta/content-security-policy/gen/top.http-rp/script-src-self/script-tag.https.html.ini
@@ -1,13 +1,4 @@
[script-tag.https.html]
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and keep-origin redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and no-redirect redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and swap-origin redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.http.html.ini b/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.http.html.ini
index e29f4dd5d4e..5891a18681e 100644
--- a/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.http.html.ini
+++ b/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.http.html.ini
@@ -1,13 +1,4 @@
[script-tag.http.html]
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and keep-origin redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and no-redirect redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-http origin and swap-origin redirection from http context.: securitypolicyviolation]
- expected: FAIL
-
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.https.html.ini b/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.https.html.ini
index bbe30519d0b..699a0dd6238 100644
--- a/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.https.html.ini
+++ b/tests/wpt/meta/content-security-policy/gen/top.meta/script-src-self/script-tag.https.html.ini
@@ -1,13 +1,4 @@
[script-tag.https.html]
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and keep-origin redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and no-redirect redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
- [Content Security Policy: Expects blocked for script-tag to cross-https origin and swap-origin redirection from https context.: securitypolicyviolation]
- expected: FAIL
-
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini b/tests/wpt/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini
deleted file mode 100644
index 213ed2d4692..00000000000
--- a/tests/wpt/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[to-javascript-url-script-src.html]
- expected: TIMEOUT
- [<iframe src='javascript:'> blocked without 'unsafe-inline'.]
- expected: TIMEOUT
-
- [<iframe> navigated to 'javascript:' blocked without 'unsafe-inline'.]
- expected: NOTRUN
-
- [<iframe src='...'> with 'unsafe-inline' navigated to 'javascript:' blocked in this document]
- expected: NOTRUN
-
- [<iframe src='...'> without 'unsafe-inline' navigated to 'javascript:' blocked in this document.]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/reporting/report-original-url.sub.html.ini b/tests/wpt/meta/content-security-policy/reporting/report-original-url.sub.html.ini
index 9d64a7e6bc4..66a2ee93f3b 100644
--- a/tests/wpt/meta/content-security-policy/reporting/report-original-url.sub.html.ini
+++ b/tests/wpt/meta/content-security-policy/reporting/report-original-url.sub.html.ini
@@ -1,11 +1,5 @@
[report-original-url.sub.html]
expected: TIMEOUT
- [Direct block, same-origin = full URL in report]
- expected: TIMEOUT
-
- [Direct block, cross-origin = full URL in report]
- expected: TIMEOUT
-
[Block after redirect, same-origin = original URL in report]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini
deleted file mode 100644
index 31bfeae4a12..00000000000
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[script-src-report-only-policy-works-with-hash-policy.html]
- expected: TIMEOUT
- [Test that the securitypolicyviolation event is fired]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-eval.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-eval.html.ini
deleted file mode 100644
index bebd42f2743..00000000000
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-eval.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[blockeduri-eval.html]
- expected: TIMEOUT
- [Eval violations have a blockedURI of 'eval']
- expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini
index 9c191e43078..3d0febce2b5 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini
@@ -1,4 +1,3 @@
[blockeduri-inline.html]
- expected: TIMEOUT
[Inline violations have a blockedURI of 'inline']
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html.ini
index 6ebb357445f..14fa5353a94 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html.ini
@@ -1,13 +1,3 @@
[blockeduri-ws-wss-scheme.html]
- expected: TIMEOUT
- [ws]
- expected: FAIL
-
- [wss]
- expected: FAIL
-
- [cross-origin]
- expected: FAIL
-
[redirect]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/linenumber.tentative.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/linenumber.tentative.html.ini
index fed78a0aa49..e8114229ab9 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/linenumber.tentative.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/linenumber.tentative.html.ini
@@ -1,4 +1,3 @@
[linenumber.tentative.html]
- expected: TIMEOUT
[linenumber]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html.ini
index b12f81377d1..409022079e0 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html.ini
@@ -1,13 +1,7 @@
[script-sample-no-opt-in.html]
expected: TIMEOUT
- [Inline script should not have a sample.]
- expected: TIMEOUT
-
- [Inline event handlers should not have a sample.]
- expected: TIMEOUT
-
[JavaScript URLs in iframes should not have a sample.]
expected: TIMEOUT
- [eval()-alikes should not have a sample.]
+ [Inline event handlers should not have a sample.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample.html.ini
index f4c315396f6..8723775f27e 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/script-sample.html.ini
@@ -1,19 +1,7 @@
[script-sample.html]
expected: TIMEOUT
- [Inline script should have a sample.]
- expected: TIMEOUT
-
- [Inline event handlers should have a sample.]
- expected: TIMEOUT
-
[JavaScript URLs in iframes should have a sample.]
expected: TIMEOUT
- [eval() should have a sample.]
- expected: TIMEOUT
-
- [setInterval() should have a sample.]
- expected: TIMEOUT
-
- [setTimeout() should have a sample.]
+ [Inline event handlers should have a sample.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html.ini
index 03d164a4050..514f91961e3 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html.ini
@@ -1,4 +1,3 @@
[source-file-blob-scheme.html]
- expected: TIMEOUT
[Violations from data:-URL scripts have a sourceFile of 'blob']
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-data-scheme.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-data-scheme.html.ini
index 387a7e2ff98..ed4dba7d3c3 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-data-scheme.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/source-file-data-scheme.html.ini
@@ -1,4 +1,3 @@
[source-file-data-scheme.html]
- expected: TIMEOUT
[Violations from data:-URL scripts have a sourceFile of 'data']
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html.ini
index eb10ad61b2c..ef89e7cb1a9 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html.ini
@@ -1,7 +1,4 @@
[style-sample-no-opt-in.html]
expected: TIMEOUT
- [Inline style blocks should not have a sample.]
- expected: TIMEOUT
-
[Inline style attributes should not have a sample.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample.html.ini
index 460e21bd6cd..63e278182d8 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/style-sample.html.ini
@@ -1,7 +1,4 @@
[style-sample.html]
expected: TIMEOUT
- [Inline style blocks should have a sample.]
- expected: TIMEOUT
-
[Inline style attributes should have a sample.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/targeting.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/targeting.html.ini
index 88da5e48238..952c5185dd8 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/targeting.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/targeting.html.ini
@@ -4,13 +4,10 @@
expected: NOTRUN
[Inline violations target the right element.]
- expected: TIMEOUT
+ expected: FAIL
[Correct targeting inside shadow tree (inline handler).]
expected: TIMEOUT
- [Correct targeting inside shadow tree (style).]
- expected: TIMEOUT
-
[Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-attr-allowed.html.ini b/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-attr-allowed.html.ini
deleted file mode 100644
index c67fec5245c..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-attr-allowed.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-elem-blocked-attr-allowed.html]
- expected: TIMEOUT
- [Should fire a security policy violation for the inline block]
- expected: NOTRUN
-
- [The inline style should not be applied and the attribute style should be applied]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-src-allowed.html.ini b/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-src-allowed.html.ini
deleted file mode 100644
index 06439a8cc0a..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src-attr-elem/style-src-elem-blocked-src-allowed.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-elem-blocked-src-allowed.html]
- expected: TIMEOUT
- [Should fire a security policy violation event]
- expected: NOTRUN
-
- [The inline style should not be applied]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini
deleted file mode 100644
index 06132f67bfc..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[injected-inline-style-blocked.sub.html]
- [Expecting logs: ["violated-directive=style-src-elem","violated-directive=style-src-elem","PASS"\]]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/inline-style-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/inline-style-blocked.sub.html.ini
deleted file mode 100644
index 62bbd2f0e13..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/inline-style-blocked.sub.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[inline-style-blocked.sub.html]
- expected: TIMEOUT
- [Triggers securitypolicyviolation.]
- expected: TIMEOUT
-
- [Inline style element is blocked by CSP.]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini
deleted file mode 100644
index a79f011aec3..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-hash-blocked.html]
- expected: TIMEOUT
- [Should not load style that does not match hash]
- expected: FAIL
-
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-hash-case-insensitive.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-hash-case-insensitive.html.ini
new file mode 100644
index 00000000000..fe35d3ea411
--- /dev/null
+++ b/tests/wpt/meta/content-security-policy/style-src/style-src-hash-case-insensitive.html.ini
@@ -0,0 +1,3 @@
+[style-src-hash-case-insensitive.html]
+ [All style elements should load because they have proper hashes]
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini
deleted file mode 100644
index fba57c0f24f..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[style-src-imported-style-blocked.html]
- expected: TIMEOUT
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini
deleted file mode 100644
index bb5c48df1b0..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-injected-inline-style-blocked.html]
- expected: TIMEOUT
- [Injected style attributes should not be applied]
- expected: FAIL
-
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini
deleted file mode 100644
index 0b431bab548..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[style-src-injected-stylesheet-blocked.sub.html]
- expected: TIMEOUT
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini
deleted file mode 100644
index 33ee0df35af..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-inline-style-blocked.html]
- expected: TIMEOUT
- [Inline style element should not load without 'unsafe-inline']
- expected: FAIL
-
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini
index 63a1c9b6240..eb2f1c46fbb 100644
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini
+++ b/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini
@@ -1,7 +1,4 @@
[style-src-inline-style-nonce-blocked-error-event.html]
expected: TIMEOUT
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
-
[Test that paragraph remains unmodified and error events received.]
expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini
deleted file mode 100644
index df0fb590691..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[style-src-inline-style-nonce-blocked.html]
- expected: TIMEOUT
- [Should not load inline style element with invalid nonce]
- expected: FAIL
-
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-none-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-none-blocked.html.ini
deleted file mode 100644
index c3014b37c31..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-none-blocked.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[style-src-none-blocked.html]
- expected: TIMEOUT
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini b/tests/wpt/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini
deleted file mode 100644
index b8645f13da7..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[style-src-stylesheet-nonce-blocked.html]
- expected: TIMEOUT
- [Should fire a securitypolicyviolation event]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini
deleted file mode 100644
index 10375077b42..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[stylehash-basic-blocked.sub.html]
- [Expecting alerts: ["PASS: The 'p' element's text is green, which means the style was correctly applied.", "violated-directive=style-src-elem"\]]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini
deleted file mode 100644
index ae2f83c41d8..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[stylenonce-allowed.sub.html]
- expected: TIMEOUT
- [Should fire securitypolicyviolation]
- expected: NOTRUN
-
- [stylenonce-allowed]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini
deleted file mode 100644
index 97a86a69eea..00000000000
--- a/tests/wpt/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[stylenonce-blocked.sub.html]
- expected: TIMEOUT
- [Should fire securitypolicyviolation]
- expected: NOTRUN
-
- [stylenonce-blocked]
- expected: FAIL
diff --git a/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini b/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini
deleted file mode 100644
index 15f02f181e4..00000000000
--- a/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[serializing-html-fragments-customized-builtins.html]
- ["is" value should be serialized if the custom element has no "is" content attribute]
- expected: FAIL
-
- ["is" value should be serialized even for an undefined element]
- expected: FAIL
diff --git a/tests/wpt/meta/fetch/metadata/report.https.sub.html.ini b/tests/wpt/meta/fetch/metadata/report.https.sub.html.ini
index 058151d81ce..0348be9f384 100644
--- a/tests/wpt/meta/fetch/metadata/report.https.sub.html.ini
+++ b/tests/wpt/meta/fetch/metadata/report.https.sub.html.ini
@@ -1,2 +1,10 @@
[report.https.sub.html]
- expected: TIMEOUT
+ expected: ERROR
+ [same-origin report]
+ expected: TIMEOUT
+
+ [same-site report]
+ expected: TIMEOUT
+
+ [cross-site report]
+ expected: TIMEOUT
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
index fc885c5a594..a2502281be7 100644
--- a/tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini
+++ b/tests/wpt/meta/streams/transferable/transfer-with-messageport.window.js.ini
@@ -7,6 +7,3 @@
[Transferring a MessagePort with multiple streams should set `.ports`]
expected: FAIL
-
- [TransformStream must not be serializable]
- expected: FAIL
diff --git a/tests/wpt/meta/streams/transferable/transform-stream-members.any.js.ini b/tests/wpt/meta/streams/transferable/transform-stream-members.any.js.ini
index c5d5f43d1a4..4414054a1cf 100644
--- a/tests/wpt/meta/streams/transferable/transform-stream-members.any.js.ini
+++ b/tests/wpt/meta/streams/transferable/transform-stream-members.any.js.ini
@@ -10,14 +10,10 @@
[transform-stream-members.any.shadowrealm-in-window.html]
expected: ERROR
-[transform-stream-members.any.html]
- expected: ERROR
[transform-stream-members.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
-[transform-stream-members.any.worker.html]
- expected: ERROR
[transform-stream-members.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
diff --git a/tests/wpt/meta/streams/transferable/transform-stream.html.ini b/tests/wpt/meta/streams/transferable/transform-stream.html.ini
index dc6fe8a6c75..af9a1d42ae7 100644
--- a/tests/wpt/meta/streams/transferable/transform-stream.html.ini
+++ b/tests/wpt/meta/streams/transferable/transform-stream.html.ini
@@ -2,14 +2,5 @@
[window.postMessage should be able to transfer a TransformStream]
expected: FAIL
- [a TransformStream with a locked writable should not be transferable]
- expected: FAIL
-
- [a TransformStream with a locked readable should not be transferable]
- expected: FAIL
-
- [a TransformStream with both sides locked should not be transferable]
- expected: FAIL
-
[piping through transferred transforms should work]
expected: FAIL
diff --git a/tests/wpt/meta/streams/transferable/writable-stream.html.ini b/tests/wpt/meta/streams/transferable/writable-stream.html.ini
deleted file mode 100644
index 47326208f88..00000000000
--- a/tests/wpt/meta/streams/transferable/writable-stream.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[writable-stream.html]
- [window.postMessage should be able to transfer a {readable, writable} pair]
- expected: FAIL
diff --git a/tests/wpt/meta/streams/transform-streams/backpressure.any.js.ini b/tests/wpt/meta/streams/transform-streams/backpressure.any.js.ini
new file mode 100644
index 00000000000..099d3a6f2e0
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/backpressure.any.js.ini
@@ -0,0 +1,23 @@
+[backpressure.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[backpressure.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[backpressure.any.serviceworker.html]
+ expected: ERROR
+
+[backpressure.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[backpressure.any.sharedworker.html]
+ expected: ERROR
+
+[backpressure.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[backpressure.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[backpressure.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR \ No newline at end of file
diff --git a/tests/wpt/meta/streams/transform-streams/cancel.any.js.ini b/tests/wpt/meta/streams/transform-streams/cancel.any.js.ini
new file mode 100644
index 00000000000..7e5a1b9af50
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/cancel.any.js.ini
@@ -0,0 +1,32 @@
+[cancel.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[cancel.any.serviceworker.html]
+ expected: ERROR
+
+[cancel.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[cancel.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[cancel.any.sharedworker.html]
+ expected: ERROR
+
+[cancel.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[cancel.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[cancel.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[cancel.any.worker.html]
+ [readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()]
+ expected: FAIL
+
+
+[cancel.any.html]
+ [readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()]
+ expected: FAIL
diff --git a/tests/wpt/meta/streams/transform-streams/errors.any.js.ini b/tests/wpt/meta/streams/transform-streams/errors.any.js.ini
new file mode 100644
index 00000000000..02eaa76ca8e
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/errors.any.js.ini
@@ -0,0 +1,32 @@
+[errors.any.sharedworker.html]
+ expected: ERROR
+
+[errors.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[errors.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[errors.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[errors.any.serviceworker.html]
+ expected: ERROR
+
+[errors.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[errors.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[errors.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[errors.any.html]
+ [abort should set the close reason for the writable when it happens before cancel during start, and cancel should reject]
+ expected: FAIL
+
+
+[errors.any.worker.html]
+ [abort should set the close reason for the writable when it happens before cancel during start, and cancel should reject]
+ expected: FAIL
diff --git a/tests/wpt/meta/streams/transform-streams/flush.any.js.ini b/tests/wpt/meta/streams/transform-streams/flush.any.js.ini
new file mode 100644
index 00000000000..a2ee0101993
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/flush.any.js.ini
@@ -0,0 +1,23 @@
+[flush.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[flush.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[flush.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[flush.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[flush.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[flush.any.sharedworker.html]
+ expected: ERROR
+
+[flush.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[flush.any.serviceworker.html]
+ expected: ERROR \ No newline at end of file
diff --git a/tests/wpt/meta/streams/transform-streams/general.any.js.ini b/tests/wpt/meta/streams/transform-streams/general.any.js.ini
new file mode 100644
index 00000000000..11dfc7d4ece
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/general.any.js.ini
@@ -0,0 +1,23 @@
+[general.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[general.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[general.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[general.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[general.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[general.any.serviceworker.html]
+ expected: ERROR
+
+[general.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[general.any.sharedworker.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/streams/transform-streams/lipfuzz.any.js.ini b/tests/wpt/meta/streams/transform-streams/lipfuzz.any.js.ini
new file mode 100644
index 00000000000..5af2be4a1ae
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/lipfuzz.any.js.ini
@@ -0,0 +1,23 @@
+[lipfuzz.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[lipfuzz.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[lipfuzz.any.serviceworker.html]
+ expected: ERROR
+
+[lipfuzz.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[lipfuzz.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[lipfuzz.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[lipfuzz.any.sharedworker.html]
+ expected: ERROR
+
+[lipfuzz.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/streams/transform-streams/patched-global.any.js.ini b/tests/wpt/meta/streams/transform-streams/patched-global.any.js.ini
new file mode 100644
index 00000000000..06a324cb060
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/patched-global.any.js.ini
@@ -0,0 +1,23 @@
+[patched-global.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[patched-global.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[patched-global.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[patched-global.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[patched-global.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[patched-global.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[patched-global.any.sharedworker.html]
+ expected: ERROR
+
+[patched-global.any.serviceworker.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/streams/transform-streams/properties.any.js.ini b/tests/wpt/meta/streams/transform-streams/properties.any.js.ini
new file mode 100644
index 00000000000..f5573ee57e4
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/properties.any.js.ini
@@ -0,0 +1,23 @@
+[properties.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[properties.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[properties.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[properties.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[properties.any.sharedworker.html]
+ expected: ERROR
+
+[properties.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[properties.any.serviceworker.html]
+ expected: ERROR
+
+[properties.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/streams/transform-streams/reentrant-strategies.any.js.ini b/tests/wpt/meta/streams/transform-streams/reentrant-strategies.any.js.ini
new file mode 100644
index 00000000000..1c6b9fd51da
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/reentrant-strategies.any.js.ini
@@ -0,0 +1,23 @@
+[reentrant-strategies.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[reentrant-strategies.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[reentrant-strategies.any.sharedworker.html]
+ expected: ERROR
+
+[reentrant-strategies.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[reentrant-strategies.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[reentrant-strategies.any.serviceworker.html]
+ expected: ERROR
+
+[reentrant-strategies.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[reentrant-strategies.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/streams/transform-streams/strategies.any.js.ini b/tests/wpt/meta/streams/transform-streams/strategies.any.js.ini
new file mode 100644
index 00000000000..52c18b67fd4
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/strategies.any.js.ini
@@ -0,0 +1,24 @@
+[strategies.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[strategies.any.serviceworker.html]
+ expected: ERROR
+
+[strategies.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[strategies.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[strategies.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[strategies.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[strategies.any.sharedworker.html]
+ expected: ERROR
+
+[strategies.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
diff --git a/tests/wpt/meta/streams/transform-streams/terminate.any.js.ini b/tests/wpt/meta/streams/transform-streams/terminate.any.js.ini
new file mode 100644
index 00000000000..c81b1e40d1e
--- /dev/null
+++ b/tests/wpt/meta/streams/transform-streams/terminate.any.js.ini
@@ -0,0 +1,23 @@
+[terminate.any.serviceworker.html]
+ expected: ERROR
+
+[terminate.any.shadowrealm-in-sharedworker.html]
+ expected: ERROR
+
+[terminate.https.any.shadowrealm-in-serviceworker.html]
+ expected: ERROR
+
+[terminate.any.shadowrealm-in-window.html]
+ expected: ERROR
+
+[terminate.any.shadowrealm-in-shadowrealm.html]
+ expected: ERROR
+
+[terminate.https.any.shadowrealm-in-audioworklet.html]
+ expected: ERROR
+
+[terminate.any.shadowrealm-in-dedicatedworker.html]
+ expected: ERROR
+
+[terminate.any.sharedworker.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/trusted-types/default-policy.html.ini b/tests/wpt/meta/trusted-types/default-policy.html.ini
index 15588646951..cf57031ddbe 100644
--- a/tests/wpt/meta/trusted-types/default-policy.html.ini
+++ b/tests/wpt/meta/trusted-types/default-policy.html.ini
@@ -1,7 +1,7 @@
[default-policy.html]
- expected: TIMEOUT
+ expected: OK
[Count SecurityPolicyViolation events.]
- expected: TIMEOUT
+ expected: FAIL
[div.innerHTML no default policy]
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
index 4f06e4c971f..c3f34522557 100644
--- a/tests/wpt/meta/trusted-types/empty-default-policy.html.ini
+++ b/tests/wpt/meta/trusted-types/empty-default-policy.html.ini
@@ -1,7 +1,7 @@
[empty-default-policy.html]
- expected: TIMEOUT
+ expected: OK
[Count SecurityPolicyViolation events.]
- expected: TIMEOUT
+ expected: FAIL
[div.innerHTML default]
expected: FAIL
diff --git a/tests/wpt/meta/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html.ini b/tests/wpt/meta/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html.ini
deleted file mode 100644
index c804530024c..00000000000
--- a/tests/wpt/meta/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-src-blocks-wasm.tentative.sub.html]
- [Importing a WebAssembly module should be guarded by script-src CSP.]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini
index ad0f9714ad1..9cdf1e0d0da 100644
--- a/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini
@@ -13,9 +13,3 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
-
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/scroll_into_view.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/scroll_into_view.py.ini
index 87c9c813881..2627072cf91 100644
--- a/tests/wpt/meta/webdriver/tests/classic/element_click/scroll_into_view.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/element_click/scroll_into_view.py.ini
@@ -1,30 +1,30 @@
[scroll_into_view.py]
[test_scroll_into_view]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[9\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[8\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[7\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[6\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[5\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[4\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[3\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[2\]]
- expected: ERROR
+ expected: FAIL
[test_partially_visible_does_not_scroll[1\]]
- expected: ERROR
+ expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/form_controls.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/form_controls.py.ini
index 5d4a3bd4de5..1dea194f9b2 100644
--- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/form_controls.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/form_controls.py.ini
@@ -4,3 +4,6 @@
[test_textarea_append]
expected: FAIL
+
+ [test_date]
+ expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/scroll_into_view.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/scroll_into_view.py.ini
index 3e260cade03..d141c6022db 100644
--- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/scroll_into_view.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/scroll_into_view.py.ini
@@ -1,7 +1,4 @@
[scroll_into_view.py]
- [test_element_outside_of_not_scrollable_viewport]
- expected: FAIL
-
[test_element_outside_of_scrollable_viewport]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini
index b2b09490191..10a5a86e3d2 100644
--- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini
@@ -13,9 +13,3 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
-
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/collections.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/collections.py.ini
index 5d0711fe4ad..710ae93d053 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/collections.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/collections.py.ini
@@ -1,10 +1,4 @@
[collections.py]
- [test_array_in_array]
- expected: FAIL
-
- [test_dom_token_list]
- expected: FAIL
-
[test_file_list]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_script/collections.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_script/collections.py.ini
index 68e5ec4b830..710ae93d053 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_script/collections.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_script/collections.py.ini
@@ -1,12 +1,6 @@
[collections.py]
- [test_dom_token_list]
- expected: FAIL
-
[test_file_list]
expected: FAIL
[test_html_all_collection]
expected: FAIL
-
- [test_array_in_array]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini
index abd4a7750b7..f00172fdc5a 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini
@@ -14,11 +14,5 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_computed_roles[<article>foo</article>-article-article\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini
index bcd25112776..d55c5312a47 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini
@@ -13,9 +13,3 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
-
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini
index 065e9fbc4ce..67875a58cd9 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini
@@ -14,11 +14,5 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_basic]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini
index b810c389100..0ac8ff98d59 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini
@@ -14,11 +14,5 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_get_element_tag_name]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini
index 5f04f967054..ad870f8f49b 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini
@@ -14,12 +14,6 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_transform_capitalize[space\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini b/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini
index f75724979c5..eb4c0299197 100644
--- a/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini
@@ -13,9 +13,3 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
-
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini b/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini
index 77be6174789..db51a3496ae 100644
--- a/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini
@@ -1,15 +1,9 @@
[new_tab.py]
[test_keeps_current_window_handle]
- expected: ERROR
+ expected: FAIL
[test_opens_about_blank_in_new_tab]
- expected: ERROR
+ expected: FAIL
[test_initial_selection_for_contenteditable]
- expected: ERROR
-
- [test_sets_no_window_name]
- expected: ERROR
-
- [test_sets_no_opener]
- expected: ERROR
+ expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/perform.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/perform.py.ini
deleted file mode 100644
index b4a8841b9ae..00000000000
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/perform.py.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[perform.py]
- [test_input_source_action_sequence_actions_pause_duration_valid[wheel\]]
- expected: FAIL
-
- [test_input_source_action_sequence_actions_pause_duration_missing[wheel\]]
- expected: FAIL
-
- [test_input_source_action_sequence_pointer_parameters_not_processed[wheel\]]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse.py.ini
index 4a163fe2fac..4222966b349 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse.py.ini
@@ -1,18 +1,11 @@
[pointer_mouse.py]
- expected: TIMEOUT
[test_no_top_browsing_context]
expected: FAIL
[test_no_browsing_context]
- expected: ERROR
-
- [test_pointer_down_closes_browsing_context]
- expected: FAIL
-
- [test_stale_element_reference[top_context\]]
expected: FAIL
- [test_stale_element_reference[child_context\]]
+ [test_pointer_down_closes_browsing_context]
expected: FAIL
[test_click_at_coordinates]
@@ -39,9 +32,6 @@
[test_click_element_in_shadow_tree[inner-closed\]]
expected: FAIL
- [test_click_navigation]
- expected: FAIL
-
[test_move_to_position_in_viewport[x\]]
expected: FAIL
@@ -60,5 +50,5 @@
[test_move_to_origin_position_within_frame[element\]]
expected: FAIL
- [test_invalid_element_origin]
+ [test_params_actions_origin_outside_viewport[element\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py.ini
index 8657edd79e8..3fa735ac7ea 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py.ini
@@ -1,63 +1,63 @@
[pointer_mouse_drag.py]
[test_drag_and_drop[20-0-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[20-0-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[20-0-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[0-15-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[0-15-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[0-15-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10-15-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10-15-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10-15-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-20-0-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-20-0-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-20-0-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10--15-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10--15-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[10--15-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-10--15-0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-10--15-300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop[-10--15-800\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop_with_draggable_element[0\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop_with_draggable_element[300\]]
- expected: ERROR
+ expected: FAIL
[test_drag_and_drop_with_draggable_element[800\]]
- expected: ERROR
+ expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini
index 112a4f9ddf4..8102334d66b 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini
@@ -1,27 +1,18 @@
[pointer_origin.py]
[test_viewport_inside]
- expected: ERROR
+ expected: FAIL
[test_pointer_inside]
- expected: ERROR
+ expected: FAIL
[test_element_center_point]
- expected: ERROR
+ expected: FAIL
[test_element_center_point_with_offset]
- expected: ERROR
+ expected: FAIL
[test_element_in_view_center_point_partly_visible]
- expected: ERROR
+ expected: FAIL
[test_element_larger_than_viewport]
- expected: ERROR
-
- [test_element_outside_of_view_port]
- expected: ERROR
-
- [test_viewport_outside]
- expected: ERROR
-
- [test_pointer_outside]
- expected: ERROR
+ expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_pen.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_pen.py.ini
index a3d52579f7d..5c08076b7b2 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_pen.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_pen.py.ini
@@ -8,12 +8,6 @@
[test_pointer_down_closes_browsing_context]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_pen_pointer_in_shadow_tree[outer-open\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_touch.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_touch.py.ini
index 65101d138aa..2dd2ee19891 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_touch.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_touch.py.ini
@@ -8,12 +8,6 @@
[test_pointer_down_closes_browsing_context]
expected: FAIL
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_touch_pointer_in_shadow_tree[outer-open\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/sequence.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/sequence.py.ini
deleted file mode 100644
index 54ee376545d..00000000000
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/sequence.py.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[sequence.py]
- [test_perform_no_actions_send_no_events]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/wheel.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/wheel.py.ini
index 3f6abc70f3e..c8a0364b783 100644
--- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/wheel.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/wheel.py.ini
@@ -1,19 +1,10 @@
[wheel.py]
- [test_null_response_value]
- expected: FAIL
-
[test_no_top_browsing_context]
expected: FAIL
[test_no_browsing_context]
expected: FAIL
- [test_params_actions_origin_outside_viewport[element\]]
- expected: FAIL
-
- [test_params_actions_origin_outside_viewport[viewport\]]
- expected: FAIL
-
[test_scroll_not_scrollable]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch_webelement.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch_webelement.py.ini
index 9932ab9a5d5..1f469cd85c3 100644
--- a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch_webelement.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch_webelement.py.ini
@@ -1,10 +1,4 @@
[switch_webelement.py]
- [test_frame_id_webelement_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_frame_id_webelement_stale_element_reference[child_context\]]
- expected: FAIL
-
[test_frame_id_webelement_frame[0-foo\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/screenshot.py.ini b/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/screenshot.py.ini
index 319e4bf848f..981c68641a8 100644
--- a/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/screenshot.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/screenshot.py.ini
@@ -19,12 +19,3 @@
[test_no_such_element_from_other_frame[closed\]]
expected: FAIL
-
- [test_stale_element_reference[top_context\]]
- expected: FAIL
-
- [test_stale_element_reference[child_context\]]
- expected: FAIL
-
- [test_format_and_dimensions]
- expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/iframe.py.ini b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/iframe.py.ini
deleted file mode 100644
index 62f7ab5e4da..00000000000
--- a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/iframe.py.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[iframe.py]
- [test_always_captures_top_browsing_context]
- expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 7035ae424dc..296804116f8 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -13575,14 +13575,14 @@
]
],
"interfaces.https.html": [
- "76d746b0663ed73865816e678c2536eceff31f2d",
+ "72918e837726b58740a491a9223eeeb625055ae5",
[
null,
{}
]
],
"interfaces.worker.js": [
- "8d109502622fac7266a4564de09684a3ab94118c",
+ "e86f34f261442aeaa7074c525fb4b1206219769d",
[
"mozilla/interfaces.worker.html",
{}
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
index 76d746b0663..72918e83772 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html
@@ -371,6 +371,8 @@ test_interfaces([
"WritableStream",
"WritableStreamDefaultController",
"WritableStreamDefaultWriter",
+ "TransformStream",
+ "TransformStreamDefaultController",
"WGSLLanguageFeatures",
"XMLDocument",
"XMLHttpRequest",
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
index 8d109502622..e86f34f2614 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
@@ -137,6 +137,8 @@ test_interfaces([
"WritableStream",
"WritableStreamDefaultController",
"WritableStreamDefaultWriter",
+ "TransformStream",
+ "TransformStreamDefaultController",
"WGSLLanguageFeatures",
"XMLHttpRequest",
"XMLHttpRequestEventTarget",
diff --git a/tests/wpt/tests/content-security-policy/img-src/icon-blocked.sub.html b/tests/wpt/tests/content-security-policy/img-src/icon-blocked.sub.html
index cc882347a1a..4c39e5dec73 100644
--- a/tests/wpt/tests/content-security-policy/img-src/icon-blocked.sub.html
+++ b/tests/wpt/tests/content-security-policy/img-src/icon-blocked.sub.html
@@ -12,6 +12,7 @@
var t_spv = async_test("Test that spv event is fired");
window.addEventListener("securitypolicyviolation", t_spv.step_func_done(function(e) {
assert_equals(e.violatedDirective, 'img-src');
+ assert_equals(e.target, document);
assert_true(e.blockedURI.endsWith('/support/fail.png'));
}));
diff --git a/tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html b/tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html
new file mode 100644
index 00000000000..3b4fe7c690b
--- /dev/null
+++ b/tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="img-src 'none';">
+ <script src='/resources/testharness.js'></script>
+ <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+<p>Check that img-src sets correct target</p>
+ <script>
+ var t = async_test("Test that image does not load");
+ var t_spv = async_test("Test that spv event is fired");
+ window.addEventListener("securitypolicyviolation", t_spv.step_func_done(function(e) {
+ assert_equals(e.violatedDirective, 'img-src');
+ assert_equals(e.target, document);
+ assert_true(e.blockedURI.endsWith('/support/fail.png'));
+ }));
+ </script>
+ <img src='/content-security-policy/support/fail.png'
+ onload='t.step(function() { assert_unreached("Image should not have loaded"); t.done(); });'
+ onerror='t.done();'>
+</body>
+
+</html>
diff --git a/tests/wpt/webgl/meta/conformance/context/premultiplyalpha-test.html.ini b/tests/wpt/webgl/meta/conformance/context/premultiplyalpha-test.html.ini
deleted file mode 100644
index ffc971bc861..00000000000
--- a/tests/wpt/webgl/meta/conformance/context/premultiplyalpha-test.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[premultiplyalpha-test.html]
- bug: https://github.com/servo/servo/issues/21132
-
- [WebGL test #62]
- expected: FAIL
-
- [WebGL test #69]
- expected: FAIL