diff options
370 files changed, 9309 insertions, 7235 deletions
diff --git a/.github/workflows/pull-request-wpt-export.yml b/.github/workflows/pull-request-wpt-export.yml index aaab9d47907..2ac564dc12f 100644 --- a/.github/workflows/pull-request-wpt-export.yml +++ b/.github/workflows/pull-request-wpt-export.yml @@ -4,6 +4,10 @@ on: types: ['opened', 'synchronize', 'reopened', 'edited', 'closed'] branches: ['main'] +concurrency: + group: ${{ github.head_ref }} + cancel-in-progress: false + jobs: upstream: # Run job only on servo/servo diff --git a/Cargo.lock b/Cargo.lock index 1590681f08a..7ff8a8ec2e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,9 +199,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -214,33 +214,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.8" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", "once_cell_polyfill", @@ -1059,9 +1059,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" @@ -1070,7 +1070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "content-security-policy" version = "0.5.4" -source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#58a09ee320fd6fbb828748ae04255e4c8d3f9c9e" +source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#dc1fd32b2b32b704a43f4ae170bb2cbb80a7cf59" dependencies = [ "base64 0.22.1", "bitflags 2.9.1", @@ -1595,7 +1595,7 @@ dependencies = [ "crossbeam-channel", "devtools_traits", "embedder_traits", - "headers 0.4.0", + "headers 0.4.1", "http 1.3.1", "ipc-channel", "log", @@ -2025,7 +2025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2587,7 +2587,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3158,11 +3158,11 @@ dependencies = [ [[package]] name = "headers" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bytes", "headers-core 0.3.0", "http 1.3.1", @@ -3197,12 +3197,6 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" @@ -3416,9 +3410,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ "bytes", "futures-channel", @@ -3440,7 +3434,7 @@ name = "hyper_serde" version = "0.13.2" dependencies = [ "cookie 0.18.1", - "headers 0.4.0", + "headers 0.4.1", "http 1.3.1", "hyper 1.6.0", "mime", @@ -4046,7 +4040,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi 0.5.0", "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4865,7 +4859,7 @@ dependencies = [ "futures-core", "futures-util", "generic-array", - "headers 0.4.0", + "headers 0.4.1", "http 1.3.1", "http-body-util", "hyper 1.6.0", @@ -4918,7 +4912,7 @@ dependencies = [ "crossbeam-channel", "data-url", "embedder_traits", - "headers 0.4.0", + "headers 0.4.1", "http 1.3.1", "hyper-util", "hyper_serde", @@ -5054,11 +5048,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.5.0", "libc", ] @@ -5396,9 +5390,9 @@ dependencies = [ [[package]] name = "ohos-ime" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3ea454e31a3372cd9c4ed903db4fae861e92f57cf51852a3cd80f9d3945dcd" +checksum = "c28c803dbc0fa52e888c62c0a3573ea7559e5283ac10d1d3a75f064dba032575" dependencies = [ "log", "ohos-ime-sys", @@ -5406,9 +5400,9 @@ dependencies = [ [[package]] name = "ohos-ime-sys" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f68e03eb5b698781a69dc4918a17fe040a30be87de7014c12e4a2a3cb8a00f" +checksum = "89d326ae2b2e71f95ca756b7d418c0adcb0018889e73f7eabed59671cb179608" [[package]] name = "ohos-sys-opaque-types" @@ -5532,9 +5526,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -5848,9 +5842,9 @@ checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", "syn", @@ -6268,7 +6262,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6410,7 +6404,7 @@ dependencies = [ "fonts_traits", "fxhash", "glow", - "headers 0.4.0", + "headers 0.4.1", "html5ever", "http 1.3.1", "hyper_serde", @@ -7027,7 +7021,7 @@ dependencies = [ "getopts", "gilrs", "glow", - "headers 0.4.0", + "headers 0.4.1", "hilog", "hitrace", "image", @@ -7658,7 +7652,7 @@ dependencies = [ "getrandom", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -9075,7 +9069,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -9800,9 +9794,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "3e4a518c0ea2576f4da876349d7f67a7be489297cd77c2cf9e04c2e05fcd3974" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index c290a21f1fc..0fc9d90bf14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ mozangle = "0.5.3" net_traits = { path = "components/shared/net" } nix = "0.29" num-traits = "0.2" -num_cpus = "1.1.0" +num_cpus = "1.17.0" openxr = "0.19" parking_lot = "0.12" percent-encoding = "2.3" diff --git a/components/canvas/backend.rs b/components/canvas/backend.rs index 7e348fbc9b9..b7296b81ba3 100644 --- a/components/canvas/backend.rs +++ b/components/canvas/backend.rs @@ -2,6 +2,8 @@ * 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::borrow::Cow; + use canvas_traits::canvas::{ CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle, }; @@ -21,7 +23,6 @@ pub(crate) trait Backend: Clone + Sized { type DrawTarget: GenericDrawTarget<Self>; type PathBuilder: GenericPathBuilder<Self>; type SourceSurface; - type Bytes<'a>: AsRef<[u8]>; type Path: PathHelpers<Self> + Clone; type GradientStop; type GradientStops; @@ -122,7 +123,7 @@ pub(crate) trait GenericDrawTarget<B: Backend> { draw_options: &B::DrawOptions, ); fn surface(&self) -> B::SourceSurface; - fn bytes(&'_ self) -> B::Bytes<'_>; + fn bytes(&self) -> Cow<[u8]>; } /// A generic PathBuilder that abstracts the interface for azure's and raqote's PathBuilder. diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index ea30589d0af..0dff6744418 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -154,7 +154,18 @@ struct PathBuilderRef<'a, B: Backend> { } impl<B: Backend> PathBuilderRef<'_, B> { + /// <https://html.spec.whatwg.org/multipage#ensure-there-is-a-subpath> + fn ensure_there_is_a_subpath(&mut self, point: &Point2D<f32>) { + if self.builder.get_current_point().is_none() { + self.builder.move_to(*point); + } + } + + /// <https://html.spec.whatwg.org/multipage#dom-context-2d-lineto> fn line_to(&mut self, pt: &Point2D<f32>) { + // 2. If the object's path has no subpaths, then ensure there is a subpath for (x, y). + self.ensure_there_is_a_subpath(pt); + let pt = self.transform.transform_point(*pt); self.builder.line_to(pt); } @@ -182,14 +193,22 @@ impl<B: Backend> PathBuilderRef<'_, B> { self.move_to(&first); } + /// <https://html.spec.whatwg.org/multipage#dom-context-2d-quadraticcurveto> fn quadratic_curve_to(&mut self, cp: &Point2D<f32>, endpoint: &Point2D<f32>) { + // 2. Ensure there is a subpath for (cpx, cpy). + self.ensure_there_is_a_subpath(cp); + self.builder.quadratic_curve_to( &self.transform.transform_point(*cp), &self.transform.transform_point(*endpoint), ) } + /// <https://html.spec.whatwg.org/multipage#dom-context-2d-beziercurveto> fn bezier_curve_to(&mut self, cp1: &Point2D<f32>, cp2: &Point2D<f32>, endpoint: &Point2D<f32>) { + // 2. Ensure there is a subpath for (cp1x, cp1y). + self.ensure_there_is_a_subpath(cp1); + self.builder.bezier_curve_to( &self.transform.transform_point(*cp1), &self.transform.transform_point(*cp2), @@ -210,6 +229,7 @@ impl<B: Backend> PathBuilderRef<'_, B> { .arc(center, radius, start_angle, end_angle, ccw); } + /// <https://html.spec.whatwg.org/multipage#dom-context-2d-arcto> fn arc_to(&mut self, cp1: &Point2D<f32>, cp2: &Point2D<f32>, radius: f32) { let cp0 = if let (Some(inverse), Some(point)) = (self.transform.inverse(), self.builder.get_current_point()) @@ -218,6 +238,9 @@ impl<B: Backend> PathBuilderRef<'_, B> { } else { *cp1 }; + + // 2. Ensure there is a subpath for (x1, y1) is done by one of self.line_to calls + if (cp0.x == cp1.x && cp0.y == cp1.y) || cp1 == cp2 || radius == 0.0 { self.line_to(cp1); return; @@ -1327,7 +1350,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { .to_vec() } } else { - self.drawtarget.bytes().as_ref().to_vec() + self.drawtarget.bytes().into_owned() }; Snapshot::from_vec( diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index ecf780c36d5..02d87dfcd54 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -2,6 +2,7 @@ * 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::borrow::Cow; use std::cell::RefCell; use std::collections::HashMap; @@ -41,7 +42,6 @@ impl Backend for RaqoteBackend { type DrawTarget = raqote::DrawTarget; type PathBuilder = PathBuilder; type SourceSurface = Vec<u8>; // TODO: See if we can avoid the alloc (probably?) - type Bytes<'a> = &'a [u8]; type Path = raqote::Path; type GradientStop = raqote::GradientStop; type GradientStops = Vec<raqote::GradientStop>; @@ -656,9 +656,11 @@ impl GenericDrawTarget<RaqoteBackend> for raqote::DrawTarget { ); } #[allow(unsafe_code)] - fn bytes(&self) -> &[u8] { + fn bytes(&self) -> Cow<[u8]> { let v = self.get_data(); - unsafe { std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) } + Cow::Borrowed(unsafe { + std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) + }) } } @@ -708,7 +710,7 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder { PathOp::MoveTo(point) | PathOp::LineTo(point) => Some(Point2D::new(point.x, point.y)), PathOp::CubicTo(_, _, point) => Some(Point2D::new(point.x, point.y)), PathOp::QuadTo(_, point) => Some(Point2D::new(point.x, point.y)), - PathOp::Close => None, + PathOp::Close => path.ops.first().and_then(get_first_point), }) } @@ -731,6 +733,15 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder { } } +fn get_first_point(op: &PathOp) -> Option<euclid::Point2D<f32, euclid::UnknownUnit>> { + match op { + PathOp::MoveTo(point) | PathOp::LineTo(point) => Some(Point2D::new(point.x, point.y)), + PathOp::CubicTo(point, _, _) => Some(Point2D::new(point.x, point.y)), + PathOp::QuadTo(point, _) => Some(Point2D::new(point.x, point.y)), + PathOp::Close => None, + } +} + pub trait ToRaqoteStyle { type Target; diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index a76b0022122..0acbbec977a 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -281,6 +281,11 @@ impl PipelineDetails { } } +pub enum HitTestError { + EpochMismatch, + Others, +} + impl ServoRenderer { pub fn shutdown_state(&self) -> ShutdownState { self.shutdown_state.get() @@ -290,15 +295,19 @@ impl ServoRenderer { &self, point: DevicePoint, details_for_pipeline: impl Fn(PipelineId) -> Option<&'a PipelineDetails>, - ) -> Option<CompositorHitTestResult> { - self.hit_test_at_point_with_flags_and_pipeline( + ) -> Result<CompositorHitTestResult, HitTestError> { + match self.hit_test_at_point_with_flags_and_pipeline( point, HitTestFlags::empty(), None, details_for_pipeline, - ) - .first() - .cloned() + ) { + Ok(hit_test_results) => hit_test_results + .first() + .cloned() + .ok_or(HitTestError::Others), + Err(error) => Err(error), + } } // TODO: split this into first half (global) and second half (one for whole compositor, one for webview) @@ -308,14 +317,15 @@ impl ServoRenderer { flags: HitTestFlags, pipeline_id: Option<WebRenderPipelineId>, details_for_pipeline: impl Fn(PipelineId) -> Option<&'a PipelineDetails>, - ) -> Vec<CompositorHitTestResult> { + ) -> Result<Vec<CompositorHitTestResult>, HitTestError> { // DevicePoint and WorldPoint are the same for us. let world_point = WorldPoint::from_untyped(point.to_untyped()); let results = self.webrender_api .hit_test(self.webrender_document, pipeline_id, world_point, flags); - results + let mut epoch_mismatch = false; + let results = results .items .iter() .filter_map(|item| { @@ -323,10 +333,16 @@ impl ServoRenderer { let details = details_for_pipeline(pipeline_id)?; // If the epoch in the tag does not match the current epoch of the pipeline, - // then the hit test is against an old version of the display list and we - // should ignore this hit test for now. + // then the hit test is against an old version of the display list. match details.most_recent_display_list_epoch { - Some(epoch) if epoch.as_u16() == item.tag.1 => {}, + Some(epoch) => { + if epoch.as_u16() != item.tag.1 { + // It's too early to hit test for now. + // New scene building is in progress. + epoch_mismatch = true; + return None; + } + }, _ => return None, } @@ -340,7 +356,13 @@ impl ServoRenderer { scroll_tree_node: info.scroll_tree_node, }) }) - .collect() + .collect(); + + if epoch_mismatch { + return Err(HitTestError::EpochMismatch); + } + + Ok(results) } pub(crate) fn send_transaction(&mut self, transaction: Transaction) { @@ -619,7 +641,7 @@ impl IOCompositor { .global .borrow() .hit_test_at_point(point, details_for_pipeline); - if let Some(result) = result { + if let Ok(result) = result { self.global.borrow_mut().update_cursor(point, &result); } } @@ -649,7 +671,7 @@ impl IOCompositor { }; let dppx = webview_renderer.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer.dispatch_input_event( + webview_renderer.dispatch_point_input_event( InputEvent::MouseButton(MouseButtonEvent::new(action, button, point)) .with_webdriver_message_id(Some(message_id)), ); @@ -662,7 +684,7 @@ impl IOCompositor { }; let dppx = webview_renderer.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer.dispatch_input_event( + webview_renderer.dispatch_point_input_event( InputEvent::MouseMove(MouseMoveEvent::new(point)) .with_webdriver_message_id(Some(message_id)), ); @@ -684,7 +706,7 @@ impl IOCompositor { 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 })); + .dispatch_point_input_event(InputEvent::Wheel(WheelEvent { delta, point })); webview_renderer.on_webdriver_wheel_action(scroll_delta, point); }, @@ -792,6 +814,8 @@ impl IOCompositor { let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { return warn!("Could not find WebView for incoming display list"); }; + // WebRender is not ready until we receive "NewWebRenderFrameReady" + webview_renderer.webrender_frame_ready.set(false); let pipeline_id = display_list_info.pipeline_id; let details = webview_renderer.ensure_pipeline_details(pipeline_id.into()); @@ -841,7 +865,8 @@ impl IOCompositor { flags, pipeline, details_for_pipeline, - ); + ) + .unwrap_or_default(); let _ = sender.send(result); }, @@ -1629,11 +1654,20 @@ impl IOCompositor { }, CompositorMsg::NewWebRenderFrameReady(..) => { found_recomposite_msg = true; - compositor_messages.push(msg) + compositor_messages.push(msg); }, _ => compositor_messages.push(msg), } } + + if found_recomposite_msg { + // Process all pending events + self.webview_renderers.iter().for_each(|webview| { + webview.dispatch_pending_point_input_events(); + webview.webrender_frame_ready.set(true); + }); + } + for msg in compositor_messages { self.handle_browser_message(msg); diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index b0e91ccb02e..84d5fd877e6 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -2,9 +2,9 @@ * 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::collections::HashMap; +use std::cell::{Cell, RefCell}; use std::collections::hash_map::Keys; +use std::collections::{HashMap, VecDeque}; use std::rc::Rc; use base::id::{PipelineId, WebViewId}; @@ -25,7 +25,7 @@ use webrender_api::units::{ }; use webrender_api::{ExternalScrollId, HitTestFlags, ScrollLocation}; -use crate::compositor::{PipelineDetails, ServoRenderer}; +use crate::compositor::{HitTestError, PipelineDetails, ServoRenderer}; use crate::touch::{TouchHandler, TouchMoveAction, TouchMoveAllowed, TouchSequenceState}; // Default viewport constraints @@ -98,6 +98,10 @@ pub(crate) struct WebViewRenderer { /// Whether or not this [`WebViewRenderer`] isn't throttled and has a pipeline with /// active animations or animation frame callbacks. animating: bool, + /// Pending input events queue. Priavte and only this thread pushes events to it. + pending_point_input_events: RefCell<VecDeque<InputEvent>>, + /// WebRender is not ready between `SendDisplayList` and `WebRenderFrameReady` messages. + pub webrender_frame_ready: Cell<bool>, } impl Drop for WebViewRenderer { @@ -132,6 +136,8 @@ impl WebViewRenderer { max_viewport_zoom: None, hidpi_scale_factor: Scale::new(hidpi_scale_factor.0), animating: false, + pending_point_input_events: Default::default(), + webrender_frame_ready: Cell::default(), } } @@ -309,29 +315,89 @@ impl WebViewRenderer { } } - pub(crate) fn dispatch_input_event(&mut self, event: InputEvent) { + pub(crate) fn dispatch_point_input_event(&mut self, mut event: InputEvent) -> bool { // Events that do not need to do hit testing are sent directly to the // constellation to filter down. let Some(point) = event.point() else { - return; + return false; }; + // Delay the event if the epoch is not synchronized yet (new frame is not ready), + // or hit test result would fail and the event is rejected anyway. + if !self.webrender_frame_ready.get() || !self.pending_point_input_events.borrow().is_empty() + { + self.pending_point_input_events + .borrow_mut() + .push_back(event); + return false; + } + // If we can't find a pipeline to send this event to, we cannot continue. let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id); - let Some(result) = self + let result = match self .global .borrow() .hit_test_at_point(point, get_pipeline_details) - else { - return; + { + Ok(hit_test_results) => hit_test_results, + Err(HitTestError::EpochMismatch) => { + self.pending_point_input_events + .borrow_mut() + .push_back(event); + return false; + }, + _ => { + return false; + }, }; - self.global.borrow_mut().update_cursor(point, &result); + match event { + InputEvent::Touch(ref mut touch_event) => { + touch_event.init_sequence_id(self.touch_handler.current_sequence_id); + }, + InputEvent::MouseButton(_) | InputEvent::MouseMove(_) | InputEvent::Wheel(_) => { + self.global.borrow_mut().update_cursor(point, &result); + }, + _ => unreachable!("Unexpected input event type: {event:?}"), + } if let Err(error) = self.global.borrow().constellation_sender.send( EmbedderToConstellationMessage::ForwardInputEvent(self.id, event, Some(result)), ) { warn!("Sending event to constellation failed ({error:?})."); + false + } else { + true + } + } + + pub(crate) fn dispatch_pending_point_input_events(&self) { + while let Some(event) = self.pending_point_input_events.borrow_mut().pop_front() { + // Events that do not need to do hit testing are sent directly to the + // constellation to filter down. + let Some(point) = event.point() else { + continue; + }; + + // If we can't find a pipeline to send this event to, we cannot continue. + let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id); + let Ok(result) = self + .global + .borrow() + .hit_test_at_point(point, get_pipeline_details) + else { + // Don't need to process pending input events in this frame any more. + // TODO: Add multiple retry later if needed. + return; + }; + + self.global.borrow_mut().update_cursor(point, &result); + + if let Err(error) = self.global.borrow().constellation_sender.send( + EmbedderToConstellationMessage::ForwardInputEvent(self.id, event, Some(result)), + ) { + warn!("Sending event to constellation failed ({error:?})."); + } } } @@ -401,29 +467,11 @@ impl WebViewRenderer { } } - self.dispatch_input_event(event); + self.dispatch_point_input_event(event); } - fn send_touch_event(&self, mut event: TouchEvent) -> bool { - let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id); - let Some(result) = self - .global - .borrow() - .hit_test_at_point(event.point, get_pipeline_details) - else { - return false; - }; - - event.init_sequence_id(self.touch_handler.current_sequence_id); - let event = InputEvent::Touch(event); - if let Err(e) = self.global.borrow().constellation_sender.send( - EmbedderToConstellationMessage::ForwardInputEvent(self.id, event, Some(result)), - ) { - warn!("Sending event to constellation failed ({:?}).", e); - false - } else { - true - } + fn send_touch_event(&mut self, event: TouchEvent) -> bool { + self.dispatch_point_input_event(InputEvent::Touch(event)) } pub(crate) fn on_touch_event(&mut self, event: TouchEvent) { @@ -687,13 +735,13 @@ impl WebViewRenderer { /// <http://w3c.github.io/touch-events/#mouse-events> fn simulate_mouse_click(&mut self, point: DevicePoint) { let button = MouseButton::Left; - self.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent::new(point))); - self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent::new( + self.dispatch_point_input_event(InputEvent::MouseMove(MouseMoveEvent::new(point))); + self.dispatch_point_input_event(InputEvent::MouseButton(MouseButtonEvent::new( MouseButtonAction::Down, button, point, ))); - self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent::new( + self.dispatch_point_input_event(InputEvent::MouseButton(MouseButtonEvent::new( MouseButtonAction::Up, button, point, @@ -858,7 +906,8 @@ impl WebViewRenderer { HitTestFlags::FIND_ALL, None, get_pipeline_details, - ); + ) + .unwrap_or_default(); // Iterate through all hit test results, processing only the first node of each pipeline. // This is needed to propagate the scroll events from a pipeline representing an iframe to diff --git a/components/devtools/actors/breakpoint.rs b/components/devtools/actors/breakpoint.rs new file mode 100644 index 00000000000..04f2de140b4 --- /dev/null +++ b/components/devtools/actors/breakpoint.rs @@ -0,0 +1,55 @@ +/* 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 serde::Serialize; + +use crate::EmptyReplyMsg; +use crate::actor::{Actor, ActorMessageStatus}; +use crate::protocol::JsonPacketStream; + +#[derive(Serialize)] +pub struct BreakpointListActorMsg { + actor: String, +} + +pub struct BreakpointListActor { + name: String, +} + +impl Actor for BreakpointListActor { + fn name(&self) -> String { + self.name.clone() + } + + fn handle_message( + &self, + _registry: &crate::actor::ActorRegistry, + msg_type: &str, + _msg: &serde_json::Map<String, serde_json::Value>, + stream: &mut std::net::TcpStream, + _stream_id: crate::StreamId, + ) -> Result<crate::actor::ActorMessageStatus, ()> { + Ok(match msg_type { + "setBreakpoint" => { + let msg = EmptyReplyMsg { from: self.name() }; + let _ = stream.write_json_packet(&msg); + + ActorMessageStatus::Processed + }, + "setActiveEventBreakpoints" => { + let msg = EmptyReplyMsg { from: self.name() }; + let _ = stream.write_json_packet(&msg); + + ActorMessageStatus::Processed + }, + _ => ActorMessageStatus::Ignored, + }) + } +} + +impl BreakpointListActor { + pub fn new(name: String) -> Self { + Self { name } + } +} diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs index 81a00e82d47..fc5116131a0 100644 --- a/components/devtools/actors/browsing_context.rs +++ b/components/devtools/actors/browsing_context.rs @@ -82,6 +82,13 @@ struct BrowsingContextTraits { } #[derive(Serialize)] +#[serde(rename_all = "lowercase")] +enum TargetType { + Frame, + // Other target types not implemented yet. +} + +#[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct BrowsingContextActorMsg { actor: String, @@ -104,6 +111,7 @@ pub struct BrowsingContextActorMsg { reflow_actor: String, style_sheets_actor: String, thread_actor: String, + target_type: TargetType, // Part of the official protocol, but not yet implemented. // animations_actor: String, // changes_actor: String, @@ -302,6 +310,7 @@ impl BrowsingContextActor { reflow_actor: self.reflow.clone(), style_sheets_actor: self.style_sheets.clone(), thread_actor: self.thread.clone(), + target_type: TargetType::Frame, } } diff --git a/components/devtools/actors/watcher.rs b/components/devtools/actors/watcher.rs index 061ffc92336..7720daf070d 100644 --- a/components/devtools/actors/watcher.rs +++ b/components/devtools/actors/watcher.rs @@ -19,6 +19,7 @@ use serde::Serialize; use serde_json::{Map, Value}; use self::network_parent::{NetworkParentActor, NetworkParentActorMsg}; +use super::breakpoint::BreakpointListActor; use super::thread::ThreadActor; use super::worker::WorkerMsg; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; @@ -362,10 +363,14 @@ impl Actor for WatcherActor { ActorMessageStatus::Processed }, "getBreakpointListActor" => { + let breakpoint_list_name = registry.new_name("breakpoint-list"); + let breakpoint_list = BreakpointListActor::new(breakpoint_list_name.clone()); + registry.register_later(Box::new(breakpoint_list)); + let _ = stream.write_json_packet(&GetBreakpointListActorReply { from: self.name(), breakpoint_list: GetBreakpointListActorReplyInner { - actor: registry.new_name("breakpoint-list"), + actor: breakpoint_list_name, }, }); ActorMessageStatus::Processed diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index d097cb25e9d..74a45eaf866 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -53,6 +53,7 @@ use crate::protocol::JsonPacketStream; mod actor; /// <https://searchfox.org/mozilla-central/source/devtools/server/actors> mod actors { + pub mod breakpoint; pub mod browsing_context; pub mod console; pub mod device; diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index 33d0da952fb..e99776be350 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -170,8 +170,12 @@ pub async fn fetch_with_cors_cache( // TODO: We don't implement fetchParams as defined in the spec } -fn convert_request_to_csp_request(request: &Request, origin: &ImmutableOrigin) -> csp::Request { - csp::Request { +pub(crate) fn convert_request_to_csp_request(request: &Request) -> Option<csp::Request> { + let origin = match &request.origin { + Origin::Client => return None, + Origin::Origin(origin) => origin, + }; + let csp_request = csp::Request { url: request.url().into_url(), origin: origin.clone().into_url_origin(), redirect_count: request.redirect_count, @@ -190,45 +194,58 @@ fn convert_request_to_csp_request(request: &Request, origin: &ImmutableOrigin) - ParserMetadata::NotParserInserted => csp::ParserMetadata::NotParserInserted, ParserMetadata::Default => csp::ParserMetadata::None, }, - } + }; + Some(csp_request) } /// <https://www.w3.org/TR/CSP/#should-block-request> pub fn should_request_be_blocked_by_csp( - request: &Request, + csp_request: &csp::Request, policy_container: &PolicyContainer, ) -> (csp::CheckResult, Vec<csp::Violation>) { - let origin = match &request.origin { - Origin::Client => return (csp::CheckResult::Allowed, Vec::new()), - Origin::Origin(origin) => origin, - }; - let csp_request = convert_request_to_csp_request(request, origin); - policy_container .csp_list .as_ref() - .map(|c| c.should_request_be_blocked(&csp_request)) + .map(|c| c.should_request_be_blocked(csp_request)) .unwrap_or((csp::CheckResult::Allowed, Vec::new())) } /// <https://www.w3.org/TR/CSP/#report-for-request> pub fn report_violations_for_request_by_csp( - request: &Request, + csp_request: &csp::Request, policy_container: &PolicyContainer, ) -> Vec<csp::Violation> { - let origin = match &request.origin { - Origin::Client => return Vec::new(), - Origin::Origin(origin) => origin, - }; - let csp_request = convert_request_to_csp_request(request, origin); - policy_container .csp_list .as_ref() - .map(|c| c.report_violations_for_request(&csp_request)) + .map(|c| c.report_violations_for_request(csp_request)) .unwrap_or_default() } +fn should_response_be_blocked_by_csp( + csp_request: &csp::Request, + response: &Response, + policy_container: &PolicyContainer, +) -> (csp::CheckResult, Vec<csp::Violation>) { + if response.is_network_error() { + return (csp::CheckResult::Allowed, Vec::new()); + } + let csp_response = csp::Response { + url: response + .actual_response() + .url() + .cloned() + .expect("response must have a url") + .into_url(), + redirect_count: csp_request.redirect_count, + }; + policy_container + .csp_list + .as_ref() + .map(|c| c.should_response_to_request_be_blocked(csp_request, &csp_response)) + .unwrap_or((csp::CheckResult::Allowed, Vec::new())) +} + /// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch) pub async fn main_fetch( fetch_params: &mut FetchParams, @@ -270,13 +287,15 @@ pub async fn main_fetch( RequestPolicyContainer::Client => PolicyContainer::default(), RequestPolicyContainer::PolicyContainer(container) => container.to_owned(), }; + let csp_request = convert_request_to_csp_request(request); + if let Some(csp_request) = csp_request.as_ref() { + // Step 2.2. + let violations = report_violations_for_request_by_csp(csp_request, &policy_container); - // Step 2.2. - let violations = report_violations_for_request_by_csp(request, &policy_container); - - if !violations.is_empty() { - target.process_csp_violations(request, violations); - } + if !violations.is_empty() { + target.process_csp_violations(request, violations); + } + }; // Step 3. // TODO: handle request abort. @@ -309,22 +328,24 @@ pub async fn main_fetch( request.insecure_requests_policy ); } + if let Some(csp_request) = csp_request.as_ref() { + // Step 7. If should request be blocked due to a bad port, should fetching request be blocked + // as mixed content, or should request be blocked by Content Security Policy returns blocked, + // then set response to a network error. + let (check_result, violations) = + should_request_be_blocked_by_csp(csp_request, &policy_container); + + if !violations.is_empty() { + target.process_csp_violations(request, violations); + } - // Step 7. If should request be blocked due to a bad port, should fetching request be blocked - // as mixed content, or should request be blocked by Content Security Policy returns blocked, - // then set response to a network error. - let (check_result, violations) = should_request_be_blocked_by_csp(request, &policy_container); - - if !violations.is_empty() { - target.process_csp_violations(request, violations); - } - - if check_result == csp::CheckResult::Blocked { - warn!("Request blocked by CSP"); - response = Some(Response::network_error(NetworkError::Internal( - "Blocked by Content-Security-Policy".into(), - ))) - } + if check_result == csp::CheckResult::Blocked { + warn!("Request blocked by CSP"); + response = Some(Response::network_error(NetworkError::Internal( + "Blocked by Content-Security-Policy".into(), + ))) + } + }; if should_request_be_blocked_due_to_a_bad_port(&request.current_url()) { response = Some(Response::network_error(NetworkError::Internal( "Request attempted on bad port".into(), @@ -530,6 +551,14 @@ pub async fn main_fetch( should_be_blocked_due_to_mime_type(request.destination, &response.headers); let should_replace_with_mixed_content = !response_is_network_error && should_response_be_blocked_as_mixed_content(request, &response, &context.protocols); + let should_replace_with_csp_error = csp_request.is_some_and(|csp_request| { + let (check_result, violations) = + should_response_be_blocked_by_csp(&csp_request, &response, &policy_container); + if !violations.is_empty() { + target.process_csp_violations(request, violations); + } + check_result == csp::CheckResult::Blocked + }); // Step 15. let mut network_error_response = response @@ -553,7 +582,7 @@ pub async fn main_fetch( // Step 19. If response is not a network error and any of the following returns blocked // * should internalResponse to request be blocked as mixed content - // TODO: * should internalResponse to request be blocked by Content Security Policy + // * should internalResponse to request be blocked by Content Security Policy // * should internalResponse to request be blocked due to its MIME type // * should internalResponse to request be blocked due to nosniff let mut blocked_error_response; @@ -572,6 +601,10 @@ pub async fn main_fetch( blocked_error_response = Response::network_error(NetworkError::Internal("Blocked as mixed content".into())); &blocked_error_response + } else if should_replace_with_csp_error { + blocked_error_response = + Response::network_error(NetworkError::Internal("Blocked due to CSP".into())); + &blocked_error_response } else { internal_response }; diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs index 128436ac47c..8ad7df5d376 100644 --- a/components/net/websocket_loader.rs +++ b/components/net/websocket_loader.rs @@ -43,7 +43,8 @@ use crate::async_runtime::HANDLE; use crate::connector::{CACertificates, TlsConfig, create_tls_config}; use crate::cookie::ServoCookie; use crate::fetch::methods::{ - should_request_be_blocked_by_csp, should_request_be_blocked_due_to_a_bad_port, + convert_request_to_csp_request, should_request_be_blocked_by_csp, + should_request_be_blocked_due_to_a_bad_port, }; use crate::hosts::replace_host; use crate::http_loader::HttpState; @@ -390,14 +391,18 @@ fn connect( RequestPolicyContainer::PolicyContainer(container) => container.to_owned(), }; - let (check_result, violations) = should_request_be_blocked_by_csp(&request, &policy_container); + if let Some(csp_request) = convert_request_to_csp_request(&request) { + let (check_result, violations) = + should_request_be_blocked_by_csp(&csp_request, &policy_container); - if !violations.is_empty() { - let _ = resource_event_sender.send(WebSocketNetworkEvent::ReportCSPViolations(violations)); - } + if !violations.is_empty() { + let _ = + resource_event_sender.send(WebSocketNetworkEvent::ReportCSPViolations(violations)); + } - if check_result == csp::CheckResult::Blocked { - return Err("Blocked by Content-Security-Policy".to_string()); + if check_result == csp::CheckResult::Blocked { + return Err("Blocked by Content-Security-Policy".to_string()); + } } let client = match create_request( diff --git a/components/script/body.rs b/components/script/body.rs index cc7870a0845..ee269fd430a 100644 --- a/components/script/body.rs +++ b/components/script/body.rs @@ -249,7 +249,7 @@ impl TransmitBodyConnectHandler { let rejection_handler = Box::new(TransmitBodyPromiseRejectionHandler { bytes_sender, - stream: rooted_stream, + stream: Dom::from_ref(&rooted_stream.clone()), control_sender, }); @@ -321,11 +321,12 @@ impl Callback for TransmitBodyPromiseHandler { /// The handler of read promises rejection of body streams used in /// <https://fetch.spec.whatwg.org/#concept-request-transmit-body>. #[derive(Clone, JSTraceable, MallocSizeOf)] +#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] struct TransmitBodyPromiseRejectionHandler { #[ignore_malloc_size_of = "Channels are hard"] #[no_trace] bytes_sender: IpcSender<BodyChunkResponse>, - stream: DomRoot<ReadableStream>, + stream: Dom<ReadableStream>, #[ignore_malloc_size_of = "Channels are hard"] #[no_trace] control_sender: IpcSender<BodyChunkRequest>, diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 93212887dc8..945470194e2 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -132,7 +132,7 @@ fn find_node_by_unique_id( document .upcast::<Node>() .traverse_preorder(ShadowIncluding::Yes) - .find(|candidate| candidate.unique_id() == node_id) + .find(|candidate| candidate.unique_id(pipeline) == node_id) }) } diff --git a/components/script/dom/abortcontroller.rs b/components/script/dom/abortcontroller.rs index 3813cfdd51a..3a7ca17220d 100644 --- a/components/script/dom/abortcontroller.rs +++ b/components/script/dom/abortcontroller.rs @@ -3,24 +3,33 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsapi::Value; -use js::rust::{Handle, HandleObject}; +use js::rust::{HandleObject, HandleValue}; +use crate::dom::abortsignal::AbortSignal; use crate::dom::bindings::codegen::Bindings::AbortControllerBinding::AbortControllerMethods; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::{CanGc, JSContext}; +/// <https://dom.spec.whatwg.org/#abortcontroller> #[dom_struct] pub(crate) struct AbortController { reflector_: Reflector, + + /// An AbortController object has an associated signal (an AbortSignal object). + signal: Dom<AbortSignal>, } impl AbortController { + /// <https://dom.spec.whatwg.org/#dom-abortcontroller-abortcontroller> fn new_inherited() -> AbortController { + // The new AbortController() constructor steps are: + // Let signal be a new AbortSignal object. + // Set this’s signal to signal. AbortController { reflector_: Reflector::new(), + signal: Dom::from_ref(&AbortSignal::new_inherited()), } } @@ -36,6 +45,12 @@ impl AbortController { can_gc, ) } + + /// <https://dom.spec.whatwg.org/#abortcontroller-signal-abort> + fn signal_abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // signal abort on controller’s signal with reason if it is given. + self.signal.signal_abort(cx, reason, can_gc); + } } impl AbortControllerMethods<crate::DomTypeHolder> for AbortController { @@ -49,5 +64,15 @@ impl AbortControllerMethods<crate::DomTypeHolder> for AbortController { } /// <https://dom.spec.whatwg.org/#dom-abortcontroller-abort> - fn Abort(&self, _cx: JSContext, _reason: Handle<'_, Value>) {} + fn Abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // The abort(reason) method steps are + // to signal abort on this with reason if it is given. + self.signal_abort(cx, reason, can_gc); + } + + /// <https://dom.spec.whatwg.org/#dom-abortcontroller-signal> + fn Signal(&self) -> DomRoot<AbortSignal> { + // The signal getter steps are to return this’s signal. + self.signal.as_rooted() + } } diff --git a/components/script/dom/abortsignal.rs b/components/script/dom/abortsignal.rs index 57c6e9cd67e..e93a7b64e90 100644 --- a/components/script/dom/abortsignal.rs +++ b/components/script/dom/abortsignal.rs @@ -2,18 +2,37 @@ * 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::mem; + use dom_struct::dom_struct; -use js::jsapi::Heap; -use js::jsval::JSVal; -use js::rust::{HandleObject, MutableHandleValue}; +use js::jsapi::{ExceptionStackBehavior, Heap, JS_SetPendingException}; +use js::jsval::{JSVal, UndefinedValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; +use script_bindings::inheritance::Castable; use crate::dom::bindings::codegen::Bindings::AbortSignalBinding::AbortSignalMethods; -use crate::dom::bindings::reflector::reflect_dom_object_with_proto; +use crate::dom::bindings::error::{Error, ErrorToJsval}; +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto}; use crate::dom::bindings::root::DomRoot; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::{CanGc, JSContext}; +/// <https://dom.spec.whatwg.org/#abortcontroller-api-integration> +/// TODO: implement algorithms at call point, +/// in order to integrate the abort signal with its various use cases. +#[derive(JSTraceable, MallocSizeOf)] +#[allow(dead_code)] +enum AbortAlgorithm { + /// <https://dom.spec.whatwg.org/#add-an-event-listener> + DomEventLister, + /// <https://streams.spec.whatwg.org/#readable-stream-pipe-to> + StreamPiping, + /// <https://fetch.spec.whatwg.org/#dom-global-fetch> + Fetch, +} + /// <https://dom.spec.whatwg.org/#abortsignal> #[dom_struct] pub(crate) struct AbortSignal { @@ -22,14 +41,17 @@ pub(crate) struct AbortSignal { /// <https://dom.spec.whatwg.org/#abortsignal-abort-reason> #[ignore_malloc_size_of = "mozjs"] abort_reason: Heap<JSVal>, + + /// <https://dom.spec.whatwg.org/#abortsignal-abort-algorithms> + abort_algorithms: RefCell<Vec<AbortAlgorithm>>, } impl AbortSignal { - #[allow(dead_code)] - fn new_inherited() -> AbortSignal { + pub(crate) fn new_inherited() -> AbortSignal { AbortSignal { eventtarget: EventTarget::new_inherited(), abort_reason: Default::default(), + abort_algorithms: Default::default(), } } @@ -46,24 +68,88 @@ impl AbortSignal { can_gc, ) } + + /// <https://dom.spec.whatwg.org/#abortsignal-signal-abort> + pub(crate) fn signal_abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // If signal is aborted, then return. + if self.Aborted() { + return; + } + + let abort_reason = reason.get(); + + // Set signal’s abort reason to reason if it is given; + if !abort_reason.is_undefined() { + self.abort_reason.set(abort_reason); + } else { + // otherwise to a new "AbortError" DOMException. + rooted!(in(*cx) let mut rooted_error = UndefinedValue()); + Error::Abort.to_jsval(cx, &self.global(), rooted_error.handle_mut(), can_gc); + self.abort_reason.set(rooted_error.get()) + } + + // Let dependentSignalsToAbort be a new list. + // For each dependentSignal of signal’s dependent signals: + // TODO: #36936 + + // Run the abort steps for signal. + self.run_the_abort_steps(can_gc); + + // For each dependentSignal of dependentSignalsToAbort, run the abort steps for dependentSignal. + // TODO: #36936 + } + + /// <https://dom.spec.whatwg.org/#run-the-abort-steps> + fn run_the_abort_steps(&self, can_gc: CanGc) { + // For each algorithm of signal’s abort algorithms: run algorithm. + let algos = mem::take(&mut *self.abort_algorithms.borrow_mut()); + for _algo in algos { + // TODO: match on variant and implement algo steps. + // See the various items of #34866 + } + + // Empty signal’s abort algorithms. + // Done above with `take`. + + // Fire an event named abort at signal. + self.upcast::<EventTarget>() + .fire_event(atom!("abort"), can_gc); + } + + /// <https://dom.spec.whatwg.org/#abortsignal-aborted> + fn aborted(&self) -> bool { + // An AbortSignal object is aborted when its abort reason is not undefined. + !self.abort_reason.get().is_undefined() + } } impl AbortSignalMethods<crate::DomTypeHolder> for AbortSignal { /// <https://dom.spec.whatwg.org/#dom-abortsignal-aborted> fn Aborted(&self) -> bool { - // TODO - false + // The aborted getter steps are to return true if this is aborted; otherwise false. + self.aborted() } /// <https://dom.spec.whatwg.org/#dom-abortsignal-reason> - fn Reason(&self, _: JSContext, _rval: MutableHandleValue) { - // TODO + fn Reason(&self, _cx: JSContext, mut rval: MutableHandleValue) { + // The reason getter steps are to return this’s abort reason. + rval.set(self.abort_reason.get()); } /// <https://dom.spec.whatwg.org/#dom-abortsignal-throwifaborted> #[allow(unsafe_code)] fn ThrowIfAborted(&self) { - // TODO + // The throwIfAborted() method steps are to throw this’s abort reason, if this is aborted. + if self.aborted() { + let cx = GlobalScope::get_cx(); + unsafe { + JS_SetPendingException( + *cx, + self.abort_reason.handle(), + ExceptionStackBehavior::Capture, + ) + }; + } } // <https://dom.spec.whatwg.org/#dom-abortsignal-onabort> diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 311991804e9..ed4c37c4378 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -121,7 +121,7 @@ use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlfieldsetelement::HTMLFieldSetElement; use crate::dom::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers}; use crate::dom::htmlformelement::FormControlElementHelpers; -use crate::dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers}; +use crate::dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers, SizePresentationalHint}; use crate::dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods}; use crate::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; use crate::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; @@ -1306,6 +1306,47 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> { PropertyDeclaration::PaddingRight(cellpadding), )); } + + // https://html.spec.whatwg.org/multipage/#the-hr-element-2 + if let Some(size_info) = self + .downcast::<HTMLHRElement>() + .and_then(|hr_element| hr_element.get_size_info()) + { + match size_info { + SizePresentationalHint::SetHeightTo(height) => { + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::Height(height), + )); + }, + SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => { + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::BorderLeftWidth(border_width.clone()), + )); + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::BorderRightWidth(border_width.clone()), + )); + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::BorderTopWidth(border_width.clone()), + )); + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::BorderBottomWidth(border_width), + )); + }, + SizePresentationalHint::SetBottomBorderWidthToZero => { + hints.push(from_declaration( + shared_lock, + PropertyDeclaration::BorderBottomWidth( + specified::border::BorderSideWidth::from_px(0.), + ), + )); + }, + } + } } fn get_span(self) -> Option<u32> { @@ -4481,7 +4522,9 @@ impl SelectorsElement for SelectorWrapper<'_> { // a string containing commas (separating each language tag in // a list) but the pseudo-class instead should be parsing and // storing separate <ident> or <string>s for each language tag. - NonTSPseudoClass::Lang(ref lang) => extended_filtering(&self.get_lang(), lang), + NonTSPseudoClass::Lang(ref lang) => { + extended_filtering(&self.upcast::<Node>().get_lang().unwrap_or_default(), lang) + }, NonTSPseudoClass::ReadOnly => { !Element::state(self).contains(NonTSPseudoClass::ReadWrite.state_flag()) @@ -4821,24 +4864,7 @@ impl Element { } } - // https://html.spec.whatwg.org/multipage/#language - pub(crate) fn get_lang(&self) -> String { - self.upcast::<Node>() - .inclusive_ancestors(ShadowIncluding::Yes) - .filter_map(|node| { - node.downcast::<Element>().and_then(|el| { - el.get_attribute(&ns!(xml), &local_name!("lang")) - .or_else(|| el.get_attribute(&ns!(), &local_name!("lang"))) - .map(|attr| String::from(attr.Value())) - }) - // TODO: Check meta tags for a pragma-set default language - // TODO: Check HTTP Content-Language header - }) - .next() - .unwrap_or(String::new()) - } - - pub(crate) fn state(&self) -> ElementState { + pub fn state(&self) -> ElementState { self.state.get() } diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs index 743ced42a4b..345038a08da 100644 --- a/components/script/dom/event.rs +++ b/components/script/dom/event.rs @@ -1124,7 +1124,13 @@ impl TaskOnce for EventTask { let target = self.target.root(); let bubbles = self.bubbles; let cancelable = self.cancelable; - target.fire_event_with_params(self.name, bubbles, cancelable, CanGc::note()); + target.fire_event_with_params( + self.name, + bubbles, + cancelable, + EventComposed::NotComposed, + CanGc::note(), + ); } } diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs index 7cf7bd6106f..3e0070f91d7 100644 --- a/components/script/dom/eventsource.rs +++ b/components/script/dom/eventsource.rs @@ -61,6 +61,34 @@ enum ReadyState { Closed = 2, } +#[derive(JSTraceable, MallocSizeOf)] +struct DroppableEventSource { + canceller: DomRefCell<FetchCanceller>, +} + +impl DroppableEventSource { + pub(crate) fn new(canceller: DomRefCell<FetchCanceller>) -> Self { + DroppableEventSource { canceller } + } + + pub(crate) fn cancel(&self) { + self.canceller.borrow_mut().cancel(); + } + + pub(crate) fn set_canceller(&self, data: FetchCanceller) { + *self.canceller.borrow_mut() = data; + } +} + +// https://html.spec.whatwg.org/multipage/#garbage-collection-2 +impl Drop for DroppableEventSource { + fn drop(&mut self) { + // If an EventSource object is garbage collected while its connection is still open, + // the user agent must abort any instance of the fetch algorithm opened by this EventSource. + self.cancel(); + } +} + #[dom_struct] pub(crate) struct EventSource { eventtarget: EventTarget, @@ -74,7 +102,7 @@ pub(crate) struct EventSource { ready_state: Cell<ReadyState>, with_credentials: bool, - canceller: DomRefCell<FetchCanceller>, + droppable: DroppableEventSource, } enum ParserState { @@ -480,7 +508,7 @@ impl EventSource { ready_state: Cell::new(ReadyState::Connecting), with_credentials, - canceller: DomRefCell::new(Default::default()), + droppable: DroppableEventSource::new(DomRefCell::new(Default::default())), } } @@ -501,7 +529,7 @@ impl EventSource { // https://html.spec.whatwg.org/multipage/#sse-processing-model:fail-the-connection-3 pub(crate) fn cancel(&self) { - self.canceller.borrow_mut().cancel(); + self.droppable.cancel(); self.fail_the_connection(); } @@ -529,15 +557,6 @@ impl EventSource { } } -// https://html.spec.whatwg.org/multipage/#garbage-collection-2 -impl Drop for EventSource { - fn drop(&mut self) { - // If an EventSource object is garbage collected while its connection is still open, - // the user agent must abort any instance of the fetch algorithm opened by this EventSource. - self.canceller.borrow_mut().cancel(); - } -} - impl EventSourceMethods<crate::DomTypeHolder> for EventSource { // https://html.spec.whatwg.org/multipage/#dom-eventsource fn Constructor( @@ -632,7 +651,7 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource { listener.notify_fetch(message.unwrap()); }), ); - *ev.canceller.borrow_mut() = FetchCanceller::new(request.id); + ev.droppable.set_canceller(FetchCanceller::new(request.id)); global .core_resource_thread() .send(CoreResourceMsg::Fetch( @@ -672,7 +691,7 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource { fn Close(&self) { let GenerationId(prev_id) = self.generation_id.get(); self.generation_id.set(GenerationId(prev_id + 1)); - self.canceller.borrow_mut().cancel(); + self.droppable.cancel(); self.ready_state.set(ReadyState::Closed); } } diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 1a5aafb0ae7..15f77f5fcd5 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -59,7 +59,7 @@ use crate::dom::bindings::trace::HashMapTracedValues; use crate::dom::document::Document; use crate::dom::element::Element; use crate::dom::errorevent::ErrorEvent; -use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; +use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed, EventStatus}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlformelement::FormControlElementHelpers; use crate::dom::node::{Node, NodeTraits}; @@ -767,6 +767,7 @@ impl EventTarget { name, EventBubbles::DoesNotBubble, EventCancelable::NotCancelable, + EventComposed::NotComposed, can_gc, ) } @@ -777,6 +778,7 @@ impl EventTarget { name, EventBubbles::Bubbles, EventCancelable::NotCancelable, + EventComposed::NotComposed, can_gc, ) } @@ -787,6 +789,7 @@ impl EventTarget { name, EventBubbles::DoesNotBubble, EventCancelable::Cancelable, + EventComposed::NotComposed, can_gc, ) } @@ -801,19 +804,22 @@ impl EventTarget { name, EventBubbles::Bubbles, EventCancelable::Cancelable, + EventComposed::NotComposed, can_gc, ) } - // https://dom.spec.whatwg.org/#concept-event-fire + /// <https://dom.spec.whatwg.org/#concept-event-fire> pub(crate) fn fire_event_with_params( &self, name: Atom, bubbles: EventBubbles, cancelable: EventCancelable, + composed: EventComposed, can_gc: CanGc, ) -> DomRoot<Event> { let event = Event::new(&self.global(), name, bubbles, cancelable, can_gc); + event.set_composed(composed.into()); event.fire(self, can_gc); event } diff --git a/components/script/dom/htmlhrelement.rs b/components/script/dom/htmlhrelement.rs index c88a0fcf184..8dc11e4e848 100644 --- a/components/script/dom/htmlhrelement.rs +++ b/components/script/dom/htmlhrelement.rs @@ -2,11 +2,17 @@ * 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::str::FromStr; + use dom_struct::dom_struct; use html5ever::{LocalName, Prefix, local_name, ns}; use js::rust::HandleObject; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use style::color::AbsoluteColor; +use style::values::generics::NonNegative; +use style::values::specified::border::BorderSideWidth; +use style::values::specified::length::Size; +use style::values::specified::{LengthPercentage, NoCalcLength}; use crate::dom::bindings::codegen::Bindings::HTMLHRElementBinding::HTMLHRElementMethods; use crate::dom::bindings::inheritance::Castable; @@ -65,6 +71,18 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement { // https://html.spec.whatwg.org/multipage/#dom-hr-color make_legacy_color_setter!(SetColor, "color"); + // https://html.spec.whatwg.org/multipage/#dom-hr-noshade + make_bool_getter!(NoShade, "noshade"); + + // https://html.spec.whatwg.org/multipage/#dom-hr-noshade + make_bool_setter!(SetNoShade, "noshade"); + + // https://html.spec.whatwg.org/multipage/#dom-hr-size + make_getter!(Size, "size"); + + // https://html.spec.whatwg.org/multipage/#dom-hr-size + make_dimension_setter!(SetSize, "size"); + // https://html.spec.whatwg.org/multipage/#dom-hr-width make_getter!(Width, "width"); @@ -72,9 +90,20 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement { make_dimension_setter!(SetWidth, "width"); } +/// The result of applying the the presentational hint for the `size` attribute. +/// +/// (This attribute can mean different things depending on its value and other attributes) +#[allow(clippy::enum_variant_names)] +pub(crate) enum SizePresentationalHint { + SetHeightTo(Size), + SetAllBorderWidthValuesTo(BorderSideWidth), + SetBottomBorderWidthToZero, +} + pub(crate) trait HTMLHRLayoutHelpers { fn get_color(self) -> Option<AbsoluteColor>; fn get_width(self) -> LengthOrPercentageOrAuto; + fn get_size_info(self) -> Option<SizePresentationalHint>; } impl HTMLHRLayoutHelpers for LayoutDom<'_, HTMLHRElement> { @@ -92,6 +121,35 @@ impl HTMLHRLayoutHelpers for LayoutDom<'_, HTMLHRElement> { .cloned() .unwrap_or(LengthOrPercentageOrAuto::Auto) } + + fn get_size_info(self) -> Option<SizePresentationalHint> { + // https://html.spec.whatwg.org/multipage/#the-hr-element-2 + let element = self.upcast::<Element>(); + let size_value = element + .get_attr_val_for_layout(&ns!(), &local_name!("size")) + .and_then(|value| usize::from_str(value).ok()) + .filter(|value| *value != 0)?; + + let hint = if element + .get_attr_for_layout(&ns!(), &local_name!("color")) + .is_some() || + element + .get_attr_for_layout(&ns!(), &local_name!("noshade")) + .is_some() + { + SizePresentationalHint::SetAllBorderWidthValuesTo(BorderSideWidth::from_px( + size_value as f32 / 2.0, + )) + } else if size_value == 1 { + SizePresentationalHint::SetBottomBorderWidthToZero + } else { + SizePresentationalHint::SetHeightTo(Size::LengthPercentage(NonNegative( + LengthPercentage::Length(NoCalcLength::from_px((size_value - 2) as f32)), + ))) + }; + + Some(hint) + } } impl VirtualMethods for HTMLHRElement { diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index e2b31e918de..aa1323cdc5f 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -878,6 +878,9 @@ impl HTMLMediaElement { fn fetch_request(&self, offset: Option<u64>, seek_lock: Option<SeekLock>) { if self.resource_url.borrow().is_none() && self.blob_url.borrow().is_none() { eprintln!("Missing request url"); + if let Some(seek_lock) = seek_lock { + seek_lock.unlock(/* successful seek */ false); + } self.queue_dedicated_media_source_failure_steps(); return; } @@ -923,9 +926,17 @@ impl HTMLMediaElement { *current_fetch_context = Some(HTMLMediaElementFetchContext::new(request.id)); let listener = - HTMLMediaElementFetchListener::new(self, url.clone(), offset.unwrap_or(0), seek_lock); + HTMLMediaElementFetchListener::new(self, request.id, url.clone(), offset.unwrap_or(0)); self.owner_document().fetch_background(request, listener); + + // Since we cancelled the previous fetch, from now on the media element + // will only receive response data from the new fetch that's been + // initiated. This means the player can resume operation, since all subsequent data + // pushes will originate from the new seek offset. + if let Some(seek_lock) = seek_lock { + seek_lock.unlock(/* successful seek */ true); + } } // https://html.spec.whatwg.org/multipage/#concept-media-load-resource @@ -1414,6 +1425,7 @@ impl HTMLMediaElement { audio_renderer, Box::new(window.get_player_context()), ); + let player_id = player.lock().unwrap().get_id(); *self.player.borrow_mut() = Some(player); @@ -1430,7 +1442,7 @@ impl HTMLMediaElement { trace!("Player event {:?}", event); let this = trusted_node.clone(); task_source.queue(task!(handle_player_event: move || { - this.root().handle_player_event(&event, CanGc::note()); + this.root().handle_player_event(player_id, &event, CanGc::note()); })); }), ); @@ -1514,406 +1526,458 @@ impl HTMLMediaElement { } } - fn handle_player_event(&self, event: &PlayerEvent, can_gc: CanGc) { - match *event { - PlayerEvent::EndOfStream => { - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => "If the media data can be fetched but is found by inspection to be in - // an unsupported format, or can otherwise not be rendered at all" - if self.ready_state.get() < ReadyState::HaveMetadata { - self.queue_dedicated_media_source_failure_steps(); - } else { - // https://html.spec.whatwg.org/multipage/#reaches-the-end - match self.direction_of_playback() { - PlaybackDirection::Forwards => { - // Step 1. - if self.Loop() { - self.seek( - self.earliest_possible_position(), - /* approximate_for_speed*/ false, - ); - } else { - // Step 2. - // The **ended playback** condition is implemented inside of - // the HTMLMediaElementMethods::Ended method - - // Step 3. - let this = Trusted::new(self); - - self.owner_global().task_manager().media_element_task_source().queue( - task!(reaches_the_end_steps: move || { - let this = this.root(); - // Step 3.1. - this.upcast::<EventTarget>().fire_event(atom!("timeupdate"), CanGc::note()); - - // Step 3.2. - if this.Ended() && !this.Paused() { - // Step 3.2.1. - this.paused.set(true); - - // Step 3.2.2. - this.upcast::<EventTarget>().fire_event(atom!("pause"), CanGc::note()); - - // Step 3.2.3. - this.take_pending_play_promises(Err(Error::Abort)); - this.fulfill_in_flight_play_promises(|| ()); - } - - // Step 3.3. - this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note()); - }) - ); - - // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data - self.change_ready_state(ReadyState::HaveCurrentData); - } - }, + fn end_of_playback_in_forwards_direction(&self) { + // Step 1. If the media element has a loop attribute specified, then seek to the earliest + // posible position of the media resource and return. + if self.Loop() { + self.seek( + self.earliest_possible_position(), + /* approximate_for_speed*/ false, + ); + return; + } + // Step 2. The ended IDL attribute starts returning true once the event loop returns to + // step 1. + // The **ended playback** condition is implemented inside of + // the HTMLMediaElementMethods::Ended method - PlaybackDirection::Backwards => { - if self.playback_position.get() <= self.earliest_possible_position() { - self.owner_global() - .task_manager() - .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("ended")); - } - }, - } - } - }, - PlayerEvent::Error(ref error) => { - error!("Player error: {:?}", error); + // Step 3. Queue a media element task given the media element and the following steps: + let this = Trusted::new(self); - // If we have already flagged an error condition while processing - // the network response, we should silently skip any observable - // errors originating while decoding the erroneous response. - if self.in_error_state() { - return; + self.owner_global() + .task_manager() + .media_element_task_source() + .queue(task!(reaches_the_end_steps: move || { + let this = this.root(); + // Step 3.1. Fire an event named timeupdate at the media element + this.upcast::<EventTarget>().fire_event(atom!("timeupdate"), CanGc::note()); + + // Step 3.2. If the media element has ended playback, the direction of playback is + // forwards, and paused is false, then: + if this.Ended() && !this.Paused() { + // Step 3.2.1. Set the paused attribute to true + this.paused.set(true); + + // Step 3.2.2. Fire an event named pause at the media element + this.upcast::<EventTarget>().fire_event(atom!("pause"), CanGc::note()); + + // Step 3.2.3. Take pending play promises and reject pending play promises with + // the result and an "AbortError" DOMException + this.take_pending_play_promises(Err(Error::Abort)); + this.fulfill_in_flight_play_promises(|| ()); } - // https://html.spec.whatwg.org/multipage/#loading-the-media-resource:media-data-13 - // 1. The user agent should cancel the fetching process. - if let Some(ref mut current_fetch_context) = - *self.current_fetch_context.borrow_mut() - { - current_fetch_context.cancel(CancelReason::Error); - } - // 2. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_DECODE. - self.error.set(Some(&*MediaError::new( - &self.owner_window(), - MEDIA_ERR_DECODE, - can_gc, - ))); + // Step 3.3. Fire an event named ended at the media element. + this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note()); + })); - // 3. Set the element's networkState attribute to the NETWORK_IDLE value. - self.network_state.set(NetworkState::Idle); + // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data + self.change_ready_state(ReadyState::HaveCurrentData); + } - // 4. Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - self.delay_load_event(false, can_gc); + fn playback_end(&self) { + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => "If the media data can be fetched but is found by inspection to be in + // an unsupported format, or can otherwise not be rendered at all" + if self.ready_state.get() < ReadyState::HaveMetadata { + self.queue_dedicated_media_source_failure_steps(); + return; + } - // 5. Fire an event named error at the media element. - self.upcast::<EventTarget>() - .fire_event(atom!("error"), can_gc); + // https://html.spec.whatwg.org/multipage/#reaches-the-end + match self.direction_of_playback() { + PlaybackDirection::Forwards => self.end_of_playback_in_forwards_direction(), - // TODO: 6. Abort the overall resource selection algorithm. - }, - PlayerEvent::VideoFrameUpdated => { - // Check if the frame was resized - if let Some(frame) = self.video_renderer.lock().unwrap().current_frame { - self.handle_resize(Some(frame.width as u32), Some(frame.height as u32)); + PlaybackDirection::Backwards => { + if self.playback_position.get() <= self.earliest_possible_position() { + self.owner_global() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("ended")); } }, - PlayerEvent::MetadataUpdated(ref metadata) => { - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => If the media resource is found to have an audio track - if !metadata.audio_tracks.is_empty() { - for (i, _track) in metadata.audio_tracks.iter().enumerate() { - // Step 1. - let kind = match i { - 0 => DOMString::from("main"), - _ => DOMString::new(), - }; - let window = self.owner_window(); - let audio_track = AudioTrack::new( - &window, - DOMString::new(), - kind, - DOMString::new(), - DOMString::new(), - Some(&*self.AudioTracks()), - can_gc, - ); - - // Steps 2. & 3. - self.AudioTracks().add(&audio_track); - - // Step 4 - if let Some(servo_url) = self.resource_url.borrow().as_ref() { - let fragment = MediaFragmentParser::from(servo_url); - if let Some(id) = fragment.id() { - if audio_track.id() == DOMString::from(id) { - self.AudioTracks() - .set_enabled(self.AudioTracks().len() - 1, true); - } - } + } + } - if fragment.tracks().contains(&audio_track.kind().into()) { - self.AudioTracks() - .set_enabled(self.AudioTracks().len() - 1, true); - } - } + fn playback_error(&self, error: &str, can_gc: CanGc) { + error!("Player error: {:?}", error); + + // If we have already flagged an error condition while processing + // the network response, we should silently skip any observable + // errors originating while decoding the erroneous response. + if self.in_error_state() { + return; + } + + // https://html.spec.whatwg.org/multipage/#loading-the-media-resource:media-data-13 + // 1. The user agent should cancel the fetching process. + if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() { + current_fetch_context.cancel(CancelReason::Error); + } + // 2. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_DECODE. + self.error.set(Some(&*MediaError::new( + &self.owner_window(), + MEDIA_ERR_DECODE, + can_gc, + ))); + + // 3. Set the element's networkState attribute to the NETWORK_IDLE value. + self.network_state.set(NetworkState::Idle); + + // 4. Set the element's delaying-the-load-event flag to false. This stops delaying the load event. + self.delay_load_event(false, can_gc); + + // 5. Fire an event named error at the media element. + self.upcast::<EventTarget>() + .fire_event(atom!("error"), can_gc); - // Step 5. & 6, - if self.AudioTracks().enabled_index().is_none() { + // TODO: 6. Abort the overall resource selection algorithm. + } + + fn playback_metadata_updated( + &self, + metadata: &servo_media::player::metadata::Metadata, + can_gc: CanGc, + ) { + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => If the media resource is found to have an audio track + if !metadata.audio_tracks.is_empty() { + for (i, _track) in metadata.audio_tracks.iter().enumerate() { + // Step 1. + let kind = match i { + 0 => DOMString::from("main"), + _ => DOMString::new(), + }; + let window = self.owner_window(); + let audio_track = AudioTrack::new( + &window, + DOMString::new(), + kind, + DOMString::new(), + DOMString::new(), + Some(&*self.AudioTracks()), + can_gc, + ); + + // Steps 2. & 3. + self.AudioTracks().add(&audio_track); + + // Step 4 + if let Some(servo_url) = self.resource_url.borrow().as_ref() { + let fragment = MediaFragmentParser::from(servo_url); + if let Some(id) = fragment.id() { + if audio_track.id() == DOMString::from(id) { self.AudioTracks() .set_enabled(self.AudioTracks().len() - 1, true); } + } - // Steps 7. - let event = TrackEvent::new( - self.global().as_window(), - atom!("addtrack"), - false, - false, - &Some(VideoTrackOrAudioTrackOrTextTrack::AudioTrack(audio_track)), - can_gc, - ); - - event - .upcast::<Event>() - .fire(self.upcast::<EventTarget>(), can_gc); + if fragment.tracks().contains(&audio_track.kind().into()) { + self.AudioTracks() + .set_enabled(self.AudioTracks().len() - 1, true); } } - // => If the media resource is found to have a video track - if !metadata.video_tracks.is_empty() { - for (i, _track) in metadata.video_tracks.iter().enumerate() { - // Step 1. - let kind = match i { - 0 => DOMString::from("main"), - _ => DOMString::new(), - }; - let window = self.owner_window(); - let video_track = VideoTrack::new( - &window, - DOMString::new(), - kind, - DOMString::new(), - DOMString::new(), - Some(&*self.VideoTracks()), - can_gc, - ); - - // Steps 2. & 3. - self.VideoTracks().add(&video_track); - - // Step 4. - if let Some(track) = self.VideoTracks().item(0) { - if let Some(servo_url) = self.resource_url.borrow().as_ref() { - let fragment = MediaFragmentParser::from(servo_url); - if let Some(id) = fragment.id() { - if track.id() == DOMString::from(id) { - self.VideoTracks().set_selected(0, true); - } - } else if fragment.tracks().contains(&track.kind().into()) { - self.VideoTracks().set_selected(0, true); - } - } - } + // Step 5. & 6, + if self.AudioTracks().enabled_index().is_none() { + self.AudioTracks() + .set_enabled(self.AudioTracks().len() - 1, true); + } - // Step 5. & 6. - if self.VideoTracks().selected_index().is_none() { - self.VideoTracks() - .set_selected(self.VideoTracks().len() - 1, true); - } + // Steps 7. + let event = TrackEvent::new( + self.global().as_window(), + atom!("addtrack"), + false, + false, + &Some(VideoTrackOrAudioTrackOrTextTrack::AudioTrack(audio_track)), + can_gc, + ); - // Steps 7. - let event = TrackEvent::new( - self.global().as_window(), - atom!("addtrack"), - false, - false, - &Some(VideoTrackOrAudioTrackOrTextTrack::VideoTrack(video_track)), - can_gc, - ); - - event - .upcast::<Event>() - .fire(self.upcast::<EventTarget>(), can_gc); - } - } + event + .upcast::<Event>() + .fire(self.upcast::<EventTarget>(), can_gc); + } + } - // => "Once enough of the media data has been fetched to determine the duration..." + // => If the media resource is found to have a video track + if !metadata.video_tracks.is_empty() { + for (i, _track) in metadata.video_tracks.iter().enumerate() { // Step 1. - // servo-media owns the media timeline. - - // Step 2. - // XXX(ferjm) Update the timeline offset. + let kind = match i { + 0 => DOMString::from("main"), + _ => DOMString::new(), + }; + let window = self.owner_window(); + let video_track = VideoTrack::new( + &window, + DOMString::new(), + kind, + DOMString::new(), + DOMString::new(), + Some(&*self.VideoTracks()), + can_gc, + ); - // Step 3. - self.playback_position.set(0.); + // Steps 2. & 3. + self.VideoTracks().add(&video_track); // Step 4. - let previous_duration = self.duration.get(); - if let Some(duration) = metadata.duration { - self.duration.set(duration.as_secs() as f64); - } else { - self.duration.set(f64::INFINITY); + if let Some(track) = self.VideoTracks().item(0) { + if let Some(servo_url) = self.resource_url.borrow().as_ref() { + let fragment = MediaFragmentParser::from(servo_url); + if let Some(id) = fragment.id() { + if track.id() == DOMString::from(id) { + self.VideoTracks().set_selected(0, true); + } + } else if fragment.tracks().contains(&track.kind().into()) { + self.VideoTracks().set_selected(0, true); + } + } } - if previous_duration != self.duration.get() { - self.owner_global() - .task_manager() - .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("durationchange")); + + // Step 5. & 6. + if self.VideoTracks().selected_index().is_none() { + self.VideoTracks() + .set_selected(self.VideoTracks().len() - 1, true); } - // Step 5. - self.handle_resize(Some(metadata.width), Some(metadata.height)); + // Steps 7. + let event = TrackEvent::new( + self.global().as_window(), + atom!("addtrack"), + false, + false, + &Some(VideoTrackOrAudioTrackOrTextTrack::VideoTrack(video_track)), + can_gc, + ); - // Step 6. - self.change_ready_state(ReadyState::HaveMetadata); + event + .upcast::<Event>() + .fire(self.upcast::<EventTarget>(), can_gc); + } + } - // Step 7. - let mut jumped = false; - - // Step 8. - if self.default_playback_start_position.get() > 0. { - self.seek( - self.default_playback_start_position.get(), - /* approximate_for_speed*/ false, - ); - jumped = true; - } + // => "Once enough of the media data has been fetched to determine the duration..." + // Step 1. + // servo-media owns the media timeline. - // Step 9. - self.default_playback_start_position.set(0.); + // Step 2. + // XXX(ferjm) Update the timeline offset. - // Steps 10 and 11. - if let Some(servo_url) = self.resource_url.borrow().as_ref() { - let fragment = MediaFragmentParser::from(servo_url); - if let Some(start) = fragment.start() { - if start > 0. && start < self.duration.get() { - self.playback_position.set(start); - if !jumped { - self.seek(self.playback_position.get(), false) - } - } + // Step 3. + self.playback_position.set(0.); + + // Step 4. + let previous_duration = self.duration.get(); + if let Some(duration) = metadata.duration { + self.duration.set(duration.as_secs() as f64); + } else { + self.duration.set(f64::INFINITY); + } + if previous_duration != self.duration.get() { + self.owner_global() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("durationchange")); + } + + // Step 5. + self.handle_resize(Some(metadata.width), Some(metadata.height)); + + // Step 6. + self.change_ready_state(ReadyState::HaveMetadata); + + // Step 7. + let mut jumped = false; + + // Step 8. + if self.default_playback_start_position.get() > 0. { + self.seek( + self.default_playback_start_position.get(), + /* approximate_for_speed*/ false, + ); + jumped = true; + } + + // Step 9. + self.default_playback_start_position.set(0.); + + // Steps 10 and 11. + if let Some(servo_url) = self.resource_url.borrow().as_ref() { + let fragment = MediaFragmentParser::from(servo_url); + if let Some(start) = fragment.start() { + if start > 0. && start < self.duration.get() { + self.playback_position.set(start); + if !jumped { + self.seek(self.playback_position.get(), false) } } + } + } - // Step 12 & 13 are already handled by the earlier media track processing. + // Step 12 & 13 are already handled by the earlier media track processing. - // We wait until we have metadata to render the controls, so we render them - // with the appropriate size. - if self.Controls() { - self.render_controls(can_gc); - } + // We wait until we have metadata to render the controls, so we render them + // with the appropriate size. + if self.Controls() { + self.render_controls(can_gc); + } - let global = self.global(); - let window = global.as_window(); + let global = self.global(); + let window = global.as_window(); + + // Update the media session metadata title with the obtained metadata. + window.Navigator().MediaSession().update_title( + metadata + .title + .clone() + .unwrap_or(window.get_url().into_string()), + ); + } - // Update the media session metadata title with the obtained metadata. - window.Navigator().MediaSession().update_title( - metadata - .title - .clone() - .unwrap_or(window.get_url().into_string()), - ); - }, - PlayerEvent::NeedData => { - // The player needs more data. - // If we already have a valid fetch request, we do nothing. - // Otherwise, if we have no request and the previous request was - // cancelled because we got an EnoughData event, we restart - // fetching where we left. - if let Some(ref current_fetch_context) = *self.current_fetch_context.borrow() { - match current_fetch_context.cancel_reason() { - Some(reason) if *reason == CancelReason::Backoff => { - // XXX(ferjm) Ideally we should just create a fetch request from - // where we left. But keeping track of the exact next byte that the - // media backend expects is not the easiest task, so I'm simply - // seeking to the current playback position for now which will create - // a new fetch request for the last rendered frame. - self.seek(self.playback_position.get(), false) - }, - _ => (), - } + fn playback_video_frame_updated(&self) { + // Check if the frame was resized + if let Some(frame) = self.video_renderer.lock().unwrap().current_frame { + self.handle_resize(Some(frame.width as u32), Some(frame.height as u32)); + } + } + + fn playback_need_data(&self) { + // The player needs more data. + // If we already have a valid fetch request, we do nothing. + // Otherwise, if we have no request and the previous request was + // cancelled because we got an EnoughData event, we restart + // fetching where we left. + if let Some(ref current_fetch_context) = *self.current_fetch_context.borrow() { + if let Some(reason) = current_fetch_context.cancel_reason() { + // XXX(ferjm) Ideally we should just create a fetch request from + // where we left. But keeping track of the exact next byte that the + // media backend expects is not the easiest task, so I'm simply + // seeking to the current playback position for now which will create + // a new fetch request for the last rendered frame. + if *reason == CancelReason::Backoff { + self.seek(self.playback_position.get(), false); } - }, - PlayerEvent::EnoughData => { - self.change_ready_state(ReadyState::HaveEnoughData); - - // The player has enough data and it is asking us to stop pushing - // bytes, so we cancel the ongoing fetch request iff we are able - // to restart it from where we left. Otherwise, we continue the - // current fetch request, assuming that some frames will be dropped. - if let Some(ref mut current_fetch_context) = - *self.current_fetch_context.borrow_mut() - { - if current_fetch_context.is_seekable() { - current_fetch_context.cancel(CancelReason::Backoff); - } + return; + } + } + + if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() { + if let Err(e) = { + let mut data_source = current_fetch_context.data_source().borrow_mut(); + data_source.set_locked(false); + data_source.process_into_player_from_queue(self.player.borrow().as_ref().unwrap()) + } { + // If we are pushing too much data and we know that we can + // restart the download later from where we left, we cancel + // the current request. Otherwise, we continue the request + // assuming that we may drop some frames. + if e == PlayerError::EnoughData { + current_fetch_context.cancel(CancelReason::Backoff); + } + } + } + } + + fn playback_enough_data(&self) { + self.change_ready_state(ReadyState::HaveEnoughData); + + // The player has enough data and it is asking us to stop pushing + // bytes, so we cancel the ongoing fetch request iff we are able + // to restart it from where we left. Otherwise, we continue the + // current fetch request, assuming that some frames will be dropped. + if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() { + if current_fetch_context.is_seekable() { + current_fetch_context.cancel(CancelReason::Backoff); + } + } + } + + fn playback_position_changed(&self, position: u64) { + let position = position as f64; + let _ = self + .played + .borrow_mut() + .add(self.playback_position.get(), position); + self.playback_position.set(position); + self.time_marches_on(); + let media_position_state = + MediaPositionState::new(self.duration.get(), self.playbackRate.get(), position); + debug!( + "Sending media session event set position state {:?}", + media_position_state + ); + self.send_media_session_event(MediaSessionEvent::SetPositionState(media_position_state)); + } + + fn playback_seek_done(&self) { + // Continuation of + // https://html.spec.whatwg.org/multipage/#dom-media-seek + + // Step 13. + let task = MediaElementMicrotask::Seeked { + elem: DomRoot::from_ref(self), + generation_id: self.generation_id.get(), + }; + ScriptThread::await_stable_state(Microtask::MediaElement(task)); + } + + fn playback_state_changed(&self, state: &PlaybackState) { + let mut media_session_playback_state = MediaSessionPlaybackState::None_; + match *state { + PlaybackState::Paused => { + media_session_playback_state = MediaSessionPlaybackState::Paused; + if self.ready_state.get() == ReadyState::HaveMetadata { + self.change_ready_state(ReadyState::HaveEnoughData); } }, - PlayerEvent::PositionChanged(position) => { - let position = position as f64; - let _ = self - .played - .borrow_mut() - .add(self.playback_position.get(), position); - self.playback_position.set(position); - self.time_marches_on(); - let media_position_state = - MediaPositionState::new(self.duration.get(), self.playbackRate.get(), position); - debug!( - "Sending media session event set position state {:?}", - media_position_state - ); - self.send_media_session_event(MediaSessionEvent::SetPositionState( - media_position_state, - )); + PlaybackState::Playing => { + media_session_playback_state = MediaSessionPlaybackState::Playing; }, - PlayerEvent::SeekData(p, ref seek_lock) => { - self.fetch_request(Some(p), Some(seek_lock.clone())); + PlaybackState::Buffering => { + // Do not send the media session playback state change event + // in this case as a None_ state is expected to clean up the + // session. + return; }, - PlayerEvent::SeekDone(_) => { - // Continuation of - // https://html.spec.whatwg.org/multipage/#dom-media-seek - - // Step 13. - let task = MediaElementMicrotask::Seeked { - elem: DomRoot::from_ref(self), - generation_id: self.generation_id.get(), - }; - ScriptThread::await_stable_state(Microtask::MediaElement(task)); + _ => {}, + }; + debug!( + "Sending media session event playback state changed to {:?}", + media_session_playback_state + ); + self.send_media_session_event(MediaSessionEvent::PlaybackStateChange( + media_session_playback_state, + )); + } + + fn handle_player_event(&self, player_id: usize, event: &PlayerEvent, can_gc: CanGc) { + // Ignore the asynchronous event from previous player. + if self + .player + .borrow() + .as_ref() + .is_none_or(|player| player.lock().unwrap().get_id() != player_id) + { + return; + } + + match *event { + PlayerEvent::EndOfStream => self.playback_end(), + PlayerEvent::Error(ref error) => self.playback_error(error, can_gc), + PlayerEvent::VideoFrameUpdated => self.playback_video_frame_updated(), + PlayerEvent::MetadataUpdated(ref metadata) => { + self.playback_metadata_updated(metadata, can_gc) }, - PlayerEvent::StateChanged(ref state) => { - let mut media_session_playback_state = MediaSessionPlaybackState::None_; - match *state { - PlaybackState::Paused => { - media_session_playback_state = MediaSessionPlaybackState::Paused; - if self.ready_state.get() == ReadyState::HaveMetadata { - self.change_ready_state(ReadyState::HaveEnoughData); - } - }, - PlaybackState::Playing => { - media_session_playback_state = MediaSessionPlaybackState::Playing; - }, - PlaybackState::Buffering => { - // Do not send the media session playback state change event - // in this case as a None_ state is expected to clean up the - // session. - return; - }, - _ => {}, - }; - debug!( - "Sending media session event playback state changed to {:?}", - media_session_playback_state - ); - self.send_media_session_event(MediaSessionEvent::PlaybackStateChange( - media_session_playback_state, - )); + PlayerEvent::NeedData => self.playback_need_data(), + PlayerEvent::EnoughData => self.playback_enough_data(), + PlayerEvent::PositionChanged(position) => self.playback_position_changed(position), + PlayerEvent::SeekData(p, ref seek_lock) => { + self.fetch_request(Some(p), Some(seek_lock.clone())) }, + PlayerEvent::SeekDone(_) => self.playback_seek_done(), + PlayerEvent::StateChanged(ref state) => self.playback_state_changed(state), } } @@ -2659,6 +2723,80 @@ enum Resource { Url(ServoUrl), } +#[derive(Debug, MallocSizeOf, PartialEq)] +enum DataBuffer { + Payload(Vec<u8>), + EndOfStream, +} + +#[derive(MallocSizeOf)] +struct BufferedDataSource { + /// During initial setup and seeking (including clearing the buffer queue + /// and resetting the end-of-stream state), the data source should be locked and + /// any request for processing should be ignored until the media player informs us + /// via the NeedData event that it is ready to accept incoming data. + locked: Cell<bool>, + /// Temporary storage for incoming data. + buffers: VecDeque<DataBuffer>, +} + +impl BufferedDataSource { + fn new() -> BufferedDataSource { + BufferedDataSource { + locked: Cell::new(true), + buffers: VecDeque::default(), + } + } + + fn set_locked(&self, locked: bool) { + self.locked.set(locked) + } + + fn add_buffer_to_queue(&mut self, buffer: DataBuffer) { + debug_assert_ne!( + self.buffers.back(), + Some(&DataBuffer::EndOfStream), + "The media backend not expects any further data after end of stream" + ); + + self.buffers.push_back(buffer); + } + + fn process_into_player_from_queue( + &mut self, + player: &Arc<Mutex<dyn Player>>, + ) -> Result<(), PlayerError> { + // Early out if any request for processing should be ignored. + if self.locked.get() { + return Ok(()); + } + + while let Some(buffer) = self.buffers.pop_front() { + match buffer { + DataBuffer::Payload(payload) => { + if let Err(e) = player.lock().unwrap().push_data(payload) { + warn!("Could not push input data to player {:?}", e); + return Err(e); + } + }, + DataBuffer::EndOfStream => { + if let Err(e) = player.lock().unwrap().end_of_stream() { + warn!("Could not signal EOS to player {:?}", e); + return Err(e); + } + }, + } + } + + Ok(()) + } + + fn reset(&mut self) { + self.locked.set(true); + self.buffers.clear(); + } +} + /// Indicates the reason why a fetch request was cancelled. #[derive(Debug, MallocSizeOf, PartialEq)] enum CancelReason { @@ -2672,12 +2810,16 @@ enum CancelReason { #[derive(MallocSizeOf)] pub(crate) struct HTMLMediaElementFetchContext { + /// The fetch request id. + request_id: RequestId, /// Some if the request has been cancelled. cancel_reason: Option<CancelReason>, /// Indicates whether the fetched stream is seekable. is_seekable: bool, /// Indicates whether the fetched stream is origin clean. origin_clean: bool, + /// The buffered data source which to be processed by media backend. + data_source: DomRefCell<BufferedDataSource>, /// Fetch canceller. Allows cancelling the current fetch request by /// manually calling its .cancel() method or automatically on Drop. fetch_canceller: FetchCanceller, @@ -2686,13 +2828,19 @@ pub(crate) struct HTMLMediaElementFetchContext { impl HTMLMediaElementFetchContext { fn new(request_id: RequestId) -> HTMLMediaElementFetchContext { HTMLMediaElementFetchContext { + request_id, cancel_reason: None, is_seekable: false, origin_clean: true, + data_source: DomRefCell::new(BufferedDataSource::new()), fetch_canceller: FetchCanceller::new(request_id), } } + fn request_id(&self) -> RequestId { + self.request_id + } + fn is_seekable(&self) -> bool { self.is_seekable } @@ -2709,11 +2857,16 @@ impl HTMLMediaElementFetchContext { self.origin_clean = false; } + fn data_source(&self) -> &DomRefCell<BufferedDataSource> { + &self.data_source + } + fn cancel(&mut self, reason: CancelReason) { if self.cancel_reason.is_some() { return; } self.cancel_reason = Some(reason); + self.data_source.borrow_mut().reset(); self.fetch_canceller.cancel(); } @@ -2729,6 +2882,8 @@ struct HTMLMediaElementFetchListener { metadata: Option<Metadata>, /// The generation of the media element when this fetch started. generation_id: u32, + /// The fetch request id. + request_id: RequestId, /// Time of last progress notification. next_progress_event: Instant, /// Timing data for this resource. @@ -2743,10 +2898,6 @@ struct HTMLMediaElementFetchListener { /// EnoughData event uses this value to restart the download from /// the last fetched position. latest_fetched_content: u64, - /// The media player discards all data pushes until the seek block - /// is released right before pushing the data from the offset requested - /// by a seek request. - seek_lock: Option<SeekLock>, } // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list @@ -2758,11 +2909,6 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { fn process_response(&mut self, _: RequestId, metadata: Result<FetchMetadata, NetworkError>) { let elem = self.elem.root(); - if elem.generation_id.get() != self.generation_id || elem.player.borrow().is_none() { - // A new fetch request was triggered, so we ignore this response. - return; - } - if let Ok(FetchMetadata::Filtered { filtered: FilteredMetadata::Opaque | FilteredMetadata::OpaqueRedirect(_), .. @@ -2794,24 +2940,25 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { // We only set the expected input size if it changes. if content_length != self.expected_content_length { if let Some(content_length) = content_length { - if let Err(e) = elem - .player - .borrow() - .as_ref() - .unwrap() - .lock() - .unwrap() - .set_input_size(content_length) - { - warn!("Could not set player input size {:?}", e); - } else { - self.expected_content_length = Some(content_length); - } + self.expected_content_length = Some(content_length); } } } } + // Explicit media player initialization with live/seekable source. + if let Err(e) = elem + .player + .borrow() + .as_ref() + .unwrap() + .lock() + .unwrap() + .set_input_size(self.expected_content_length.unwrap_or_default()) + { + warn!("Could not set player input size {:?}", e); + } + let (status_is_ok, is_seekable) = self.metadata.as_ref().map_or((true, false), |s| { let status = &s.status; ( @@ -2841,46 +2988,29 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { fn process_response_chunk(&mut self, _: RequestId, payload: Vec<u8>) { let elem = self.elem.root(); - // If an error was received previously or if we triggered a new fetch request, - // we skip processing the payload. - if elem.generation_id.get() != self.generation_id || elem.player.borrow().is_none() { - return; - } - if let Some(ref current_fetch_context) = *elem.current_fetch_context.borrow() { - if current_fetch_context.cancel_reason().is_some() { - return; - } - } let payload_len = payload.len() as u64; - if let Some(seek_lock) = self.seek_lock.take() { - seek_lock.unlock(/* successful seek */ true); - } + // If an error was received previously, we skip processing the payload. + if let Some(ref mut current_fetch_context) = *elem.current_fetch_context.borrow_mut() { + if current_fetch_context.cancel_reason().is_some() { + return; + } - // Push input data into the player. - if let Err(e) = elem - .player - .borrow() - .as_ref() - .unwrap() - .lock() - .unwrap() - .push_data(payload) - { - // If we are pushing too much data and we know that we can - // restart the download later from where we left, we cancel - // the current request. Otherwise, we continue the request - // assuming that we may drop some frames. - if e == PlayerError::EnoughData { - if let Some(ref mut current_fetch_context) = - *elem.current_fetch_context.borrow_mut() - { + if let Err(e) = { + let mut data_source = current_fetch_context.data_source().borrow_mut(); + data_source.add_buffer_to_queue(DataBuffer::Payload(payload)); + data_source.process_into_player_from_queue(elem.player.borrow().as_ref().unwrap()) + } { + // If we are pushing too much data and we know that we can + // restart the download later from where we left, we cancel + // the current request. Otherwise, we continue the request + // assuming that we may drop some frames. + if e == PlayerError::EnoughData { current_fetch_context.cancel(CancelReason::Backoff); } + return; } - warn!("Could not push input data to player {:?}", e); - return; } self.latest_fetched_content += payload_len; @@ -2903,32 +3033,19 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { status: Result<ResourceFetchTiming, NetworkError>, ) { trace!("process response eof"); - if let Some(seek_lock) = self.seek_lock.take() { - seek_lock.unlock(/* successful seek */ false); - } let elem = self.elem.root(); - if elem.generation_id.get() != self.generation_id || elem.player.borrow().is_none() { - return; - } - // There are no more chunks of the response body forthcoming, so we can // go ahead and notify the media backend not to expect any further data. - if let Err(e) = elem - .player - .borrow() - .as_ref() - .unwrap() - .lock() - .unwrap() - .end_of_stream() - { - warn!("Could not signal EOS to player {:?}", e); - } + if let Some(ref mut current_fetch_context) = *elem.current_fetch_context.borrow_mut() { + let mut data_source = current_fetch_context.data_source().borrow_mut(); + + data_source.add_buffer_to_queue(DataBuffer::EndOfStream); + let _ = + data_source.process_into_player_from_queue(elem.player.borrow().as_ref().unwrap()); - // If an error was previously received we skip processing the payload. - if let Some(ref current_fetch_context) = *elem.current_fetch_context.borrow() { + // If an error was previously received we skip processing the payload. if let Some(CancelReason::Error) = current_fetch_context.cancel_reason() { return; } @@ -3015,28 +3132,32 @@ impl ResourceTimingListener for HTMLMediaElementFetchListener { impl PreInvoke for HTMLMediaElementFetchListener { fn should_invoke(&self) -> bool { - //TODO: finish_load needs to run at some point if the generation changes. - self.elem.root().generation_id.get() == self.generation_id + let elem = self.elem.root(); + + if elem.generation_id.get() != self.generation_id || elem.player.borrow().is_none() { + return false; + } + + // A new fetch request was triggered, so we skip processing previous request. + elem.current_fetch_context + .borrow() + .as_ref() + .is_some_and(|context| context.request_id() == self.request_id) } } impl HTMLMediaElementFetchListener { - fn new( - elem: &HTMLMediaElement, - url: ServoUrl, - offset: u64, - seek_lock: Option<SeekLock>, - ) -> Self { + fn new(elem: &HTMLMediaElement, request_id: RequestId, url: ServoUrl, offset: u64) -> Self { Self { elem: Trusted::new(elem), metadata: None, generation_id: elem.generation_id.get(), + request_id, next_progress_event: Instant::now() + Duration::from_millis(350), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), url, expected_content_length: None, latest_fetched_content: offset, - seek_lock, } } } diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 0f48c8e923f..2fd8f35c4d8 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -16,6 +16,8 @@ use embedder_traits::{SelectElementOptionOrOptgroup, SelectElementOption}; use euclid::{Size2D, Point2D, Rect}; use embedder_traits::{FormControl as EmbedderFormControl, EmbedderMsg}; +use crate::dom::bindings::refcounted::Trusted; +use crate::dom::event::{EventBubbles, EventCancelable, EventComposed}; use crate::dom::bindings::codegen::GenericBindings::HTMLOptGroupElementBinding::HTMLOptGroupElement_Binding::HTMLOptGroupElementMethods; use crate::dom::activation::Activatable; use crate::dom::attr::Attr; @@ -346,13 +348,6 @@ impl HTMLSelectElement { .SetData(displayed_text.trim().into()); } - pub(crate) fn selection_changed(&self, can_gc: CanGc) { - self.update_shadow_tree(can_gc); - - self.upcast::<EventTarget>() - .fire_bubbling_event(atom!("change"), can_gc); - } - pub(crate) fn selected_option(&self) -> Option<DomRoot<HTMLOptionElement>> { self.list_of_options() .find(|opt_elem| opt_elem.Selected()) @@ -417,12 +412,39 @@ impl HTMLSelectElement { return None; }; - if response.is_some() && response != selected_index { - self.selection_changed(can_gc); - } - response } + + /// <https://html.spec.whatwg.org/multipage/#send-select-update-notifications> + fn send_update_notifications(&self) { + // > When the user agent is to send select update notifications, queue an element task on the + // > user interaction task source given the select element to run these steps: + let this = Trusted::new(self); + self.owner_global() + .task_manager() + .user_interaction_task_source() + .queue(task!(send_select_update_notification: move || { + let this = this.root(); + + // TODO: Step 1. Set the select element's user validity to true. + + // Step 2. Fire an event named input at the select element, with the bubbles and composed + // attributes initialized to true. + this.upcast::<EventTarget>() + .fire_event_with_params( + atom!("input"), + EventBubbles::Bubbles, + EventCancelable::NotCancelable, + EventComposed::Composed, + CanGc::note(), + ); + + // Step 3. Fire an event named change at the select element, with the bubbles attribute initialized + // to true. + this.upcast::<EventTarget>() + .fire_bubbling_event(atom!("change"), CanGc::note()); + })); + } } impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement { @@ -578,21 +600,28 @@ impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement { /// <https://html.spec.whatwg.org/multipage/#dom-select-selectedindex> fn SetSelectedIndex(&self, index: i32, can_gc: CanGc) { + let mut selection_did_change = false; + let mut opt_iter = self.list_of_options(); for opt in opt_iter.by_ref().take(index as usize) { + selection_did_change |= opt.Selected(); opt.set_selectedness(false); } - if let Some(opt) = opt_iter.next() { - opt.set_selectedness(true); - opt.set_dirtiness(true); + if let Some(selected_option) = opt_iter.next() { + selection_did_change |= !selected_option.Selected(); + selected_option.set_selectedness(true); + selected_option.set_dirtiness(true); + // Reset remaining <option> elements for opt in opt_iter { + selection_did_change |= opt.Selected(); opt.set_selectedness(false); } } - // TODO: Track whether the selected element actually changed - self.update_shadow_tree(can_gc); + if selection_did_change { + self.update_shadow_tree(can_gc); + } } /// <https://html.spec.whatwg.org/multipage/#dom-cva-willvalidate> @@ -767,7 +796,6 @@ impl Activatable for HTMLSelectElement { true } - /// <https://html.spec.whatwg.org/multipage/#input-activation-behavior> fn activation_behavior(&self, _event: &Event, _target: &EventTarget, can_gc: CanGc) { let Some(selected_value) = self.show_menu(can_gc) else { // The user did not select a value @@ -775,6 +803,7 @@ impl Activatable for HTMLSelectElement { }; self.SetSelectedIndex(selected_value as i32, can_gc); + self.send_update_notifications(); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index cd0a41ab9f6..4a0aec45024 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -48,7 +48,7 @@ use style::properties::ComputedValues; use style::selector_parser::{SelectorImpl, SelectorParser}; use style::stylesheets::{Stylesheet, UrlExtraData}; use uuid::Uuid; -use xml5ever::serialize as xml_serialize; +use xml5ever::{local_name, serialize as xml_serialize}; use crate::conversions::Convert; use crate::document_loader::DocumentLoader; @@ -752,10 +752,9 @@ impl Node { } pub(crate) fn ranges_is_empty(&self) -> bool { - match self.rare_data().as_ref() { - Some(data) => data.ranges.is_empty(), - None => false, - } + self.rare_data() + .as_ref() + .is_none_or(|data| data.ranges.is_empty()) } #[inline] @@ -1261,13 +1260,13 @@ impl Node { } } - pub(crate) fn unique_id(&self) -> String { + pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String { let mut rare_data = self.ensure_rare_data(); if rare_data.unique_id.is_none() { - let id = UniqueId::new(); - ScriptThread::save_node_id(id.borrow().simple().to_string()); - rare_data.unique_id = Some(id); + let node_id = UniqueId::new(); + ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string()); + rare_data.unique_id = Some(node_id); } rare_data .unique_id @@ -1281,6 +1280,7 @@ impl Node { pub(crate) fn summarize(&self, can_gc: CanGc) -> NodeInfo { let USVString(base_uri) = self.BaseURI(); let node_type = self.NodeType(); + let pipeline = self.owner_document().window().pipeline_id(); let maybe_shadow_root = self.downcast::<ShadowRoot>(); let shadow_root_mode = maybe_shadow_root @@ -1288,7 +1288,7 @@ impl Node { .map(ShadowRootMode::convert); let host = maybe_shadow_root .map(ShadowRoot::Host) - .map(|host| host.upcast::<Node>().unique_id()); + .map(|host| host.upcast::<Node>().unique_id(pipeline)); let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| { let Some(root) = potential_host.shadow_root() else { return false; @@ -1310,12 +1310,12 @@ impl Node { .map(|style| style.Display().into()); NodeInfo { - unique_id: self.unique_id(), + unique_id: self.unique_id(pipeline), host, base_uri, parent: self .GetParentNode() - .map_or("".to_owned(), |node| node.unique_id()), + .map_or("".to_owned(), |node| node.unique_id(pipeline)), node_type, is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE, node_name: String::from(self.NodeName()), @@ -1469,6 +1469,21 @@ impl Node { .map(|data| data.element_data.borrow().styles.primary().clone()) } + /// <https://html.spec.whatwg.org/multipage/#language> + pub(crate) fn get_lang(&self) -> Option<String> { + self.inclusive_ancestors(ShadowIncluding::Yes) + .filter_map(|node| { + node.downcast::<Element>().and_then(|el| { + el.get_attribute(&ns!(xml), &local_name!("lang")) + .or_else(|| el.get_attribute(&ns!(), &local_name!("lang"))) + .map(|attr| String::from(attr.Value())) + }) + // TODO: Check meta tags for a pragma-set default language + // TODO: Check HTTP Content-Language header + }) + .next() + } + /// <https://dom.spec.whatwg.org/#assign-slotables-for-a-tree> pub(crate) fn assign_slottables_for_a_tree(&self) { // NOTE: This method traverses all descendants of the node and is potentially very @@ -2649,7 +2664,9 @@ impl Node { fn remove(node: &Node, parent: &Node, suppress_observers: SuppressObserver, can_gc: CanGc) { parent.owner_doc().add_script_and_layout_blocker(); - // Step 2. + // Step 1. Let parent be node’s parent. + // Step 2. Assert: parent is non-null. + // NOTE: We get parent as an argument instead assert!( node.GetParentNode() .is_some_and(|node_parent| &*node_parent == parent) @@ -2661,11 +2678,21 @@ impl Node { if parent.ranges_is_empty() { None } else { - // Step 1. + // Step 1. Let parent be node’s parent. + // Step 2. Assert: parent is not null. + // NOTE: We already have the parent. + + // Step 3. Let index be node’s index. let index = node.index(); - // Steps 2-3 are handled in Node::unbind_from_tree. - // Steps 4-5. + + // Steps 4-5 are handled in Node::unbind_from_tree. + + // Step 6. For each live range whose start node is parent and start offset is greater than index, + // decrease its start offset by 1. + // Step 7. For each live range whose end node is parent and end offset is greater than index, + // decrease its end offset by 1. parent.ranges().decrease_above(parent, index, 1); + // Parent had ranges, we needed the index, let's keep track of // it to avoid computing it for other ranges when calling // unbind_from_tree recursively. @@ -3909,7 +3936,12 @@ impl VirtualMethods for Node { /// <https://dom.spec.whatwg.org/#concept-node-remove> fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) { self.super_type().unwrap().unbind_from_tree(context, can_gc); - if !self.ranges_is_empty() { + + // Ranges should only drain to the parent from inclusive non-shadow + // including descendants. If we're in a shadow tree at this point then the + // unbind operation happened further up in the tree and we should not + // drain any ranges. + if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() { self.ranges().drain_to_parent(context, self); } } diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 4bf3b7fb72a..a47b060e0f2 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -344,6 +344,58 @@ impl Range { .chain(iter::once(end_clone)) .flat_map(move |node| node.content_boxes(can_gc)) } + + /// <https://dom.spec.whatwg.org/#concept-range-bp-set> + #[allow(clippy::neg_cmp_op_on_partial_ord)] + fn set_the_start_or_end( + &self, + node: &Node, + offset: u32, + start_or_end: StartOrEnd, + ) -> ErrorResult { + // Step 1. If node is a doctype, then throw an "InvalidNodeTypeError" DOMException. + if node.is_doctype() { + return Err(Error::InvalidNodeType); + } + + // Step 2. If offset is greater than node’s length, then throw an "IndexSizeError" DOMException. + if offset > node.len() { + return Err(Error::IndexSize); + } + + // Step 3. Let bp be the boundary point (node, offset). + // NOTE: We don't need this part. + + match start_or_end { + // If these steps were invoked as "set the start" + StartOrEnd::Start => { + // Step 4.1 If range’s root is not equal to node’s root, or if bp is after the range’s end, + // set range’s end to bp. + // Step 4.2 Set range’s start to bp. + self.set_start(node, offset); + if !(self.start() <= self.end()) { + self.set_end(node, offset); + } + }, + // If these steps were invoked as "set the end" + StartOrEnd::End => { + // Step 4.1 If range’s root is not equal to node’s root, or if bp is before the range’s start, + // set range’s start to bp. + // Step 4.2 Set range’s end to bp. + self.set_end(node, offset); + if !(self.end() >= self.start()) { + self.set_start(node, offset); + } + }, + } + + Ok(()) + } +} + +enum StartOrEnd { + Start, + End, } impl RangeMethods<crate::DomTypeHolder> for Range { @@ -365,43 +417,13 @@ impl RangeMethods<crate::DomTypeHolder> for Range { } /// <https://dom.spec.whatwg.org/#dom-range-setstart> - #[allow(clippy::neg_cmp_op_on_partial_ord)] fn SetStart(&self, node: &Node, offset: u32) -> ErrorResult { - if node.is_doctype() { - // Step 1. - Err(Error::InvalidNodeType) - } else if offset > node.len() { - // Step 2. - Err(Error::IndexSize) - } else { - // Step 3. - self.set_start(node, offset); - if !(self.start() <= self.end()) { - // Step 4. - self.set_end(node, offset); - } - Ok(()) - } + self.set_the_start_or_end(node, offset, StartOrEnd::Start) } /// <https://dom.spec.whatwg.org/#dom-range-setend> - #[allow(clippy::neg_cmp_op_on_partial_ord)] fn SetEnd(&self, node: &Node, offset: u32) -> ErrorResult { - if node.is_doctype() { - // Step 1. - Err(Error::InvalidNodeType) - } else if offset > node.len() { - // Step 2. - Err(Error::IndexSize) - } else { - // Step 3. - self.set_end(node, offset); - if !(self.end() >= self.start()) { - // Step 4. - self.set_start(node, offset); - } - Ok(()) - } + self.set_the_start_or_end(node, offset, StartOrEnd::End) } /// <https://dom.spec.whatwg.org/#dom-range-setstartbefore> @@ -1204,6 +1226,7 @@ impl WeakRangeVec { } /// Used for steps 2-3. when removing a node. + /// /// <https://dom.spec.whatwg.org/#concept-node-remove> pub(crate) fn drain_to_parent(&self, context: &UnbindContext, child: &Node) { if self.is_empty() { diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index d2c1d853f86..5203a5f0a83 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -1926,7 +1926,7 @@ impl ReadableStreamMethods<crate::DomTypeHolder> for ReadableStream { // If ! IsReadableStreamLocked(this) is true, // return a promise rejected with a TypeError exception. let promise = Promise::new(&global, can_gc); - promise.reject_error(Error::Type("stream is not locked".to_owned()), can_gc); + promise.reject_error(Error::Type("stream is locked".to_owned()), can_gc); promise } else { // Return ! ReadableStreamCancel(this, reason). diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 4e7c136f42b..858cd24d45d 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -797,6 +797,7 @@ impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest { if self.ready_state.get() == XMLHttpRequestState::Done { self.change_ready_state(XMLHttpRequestState::Unsent, can_gc); self.response_status.set(Err(())); + *self.status.borrow_mut() = HttpStatus::new_error(); self.response.borrow_mut().clear(); self.response_headers.borrow_mut().clear(); } @@ -1188,6 +1189,8 @@ impl XMLHttpRequest { self.discard_subsequent_responses(); self.send_flag.set(false); + *self.status.borrow_mut() = HttpStatus::new_error(); + self.response_headers.borrow_mut().clear(); // XXXManishearth set response to NetworkError self.change_ready_state(XMLHttpRequestState::Done, can_gc); return_if_fetch_was_terminated!(); diff --git a/components/script/dom/xpathresult.rs b/components/script/dom/xpathresult.rs index f4a9ae7a31b..890e559ba97 100644 --- a/components/script/dom/xpathresult.rs +++ b/components/script/dom/xpathresult.rs @@ -54,7 +54,7 @@ impl TryFrom<u16> for XPathResultType { } } -#[derive(JSTraceable, MallocSizeOf)] +#[derive(Debug, JSTraceable, MallocSizeOf)] pub(crate) enum XPathResultValue { Boolean(bool), /// A IEEE-754 double-precision floating point number diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index e138e7114d3..e7f60e23772 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -194,6 +194,8 @@ pub(crate) struct IncompleteParserContexts(RefCell<Vec<(PipelineId, ParserContex unsafe_no_jsmanaged_fields!(TaskQueue<MainThreadScriptMsg>); +type NodeIdSet = HashSet<String>; + #[derive(JSTraceable)] // ScriptThread instances are rooted on creation, so this is okay #[cfg_attr(crown, allow(crown::unrooted_must_root))] @@ -315,8 +317,9 @@ pub struct ScriptThread { #[no_trace] player_context: WindowGLContext, - /// A set of all nodes ever created in this script thread - node_ids: DomRefCell<HashSet<String>>, + /// A map from pipelines to all owned nodes ever created in this script thread + #[no_trace] + pipeline_to_node_ids: DomRefCell<HashMap<PipelineId, NodeIdSet>>, /// Code is running as a consequence of a user interaction is_user_interacting: Cell<bool>, @@ -818,14 +821,25 @@ impl ScriptThread { }) } - pub(crate) fn save_node_id(node_id: String) { + pub(crate) fn save_node_id(pipeline: PipelineId, node_id: String) { with_script_thread(|script_thread| { - script_thread.node_ids.borrow_mut().insert(node_id); + script_thread + .pipeline_to_node_ids + .borrow_mut() + .entry(pipeline) + .or_default() + .insert(node_id); }) } - pub(crate) fn has_node_id(node_id: &str) -> bool { - with_script_thread(|script_thread| script_thread.node_ids.borrow().contains(node_id)) + pub(crate) fn has_node_id(pipeline: PipelineId, node_id: &str) -> bool { + with_script_thread(|script_thread| { + script_thread + .pipeline_to_node_ids + .borrow() + .get(&pipeline) + .is_some_and(|node_ids| node_ids.contains(node_id)) + }) } /// Creates a new script thread. @@ -945,7 +959,7 @@ impl ScriptThread { unminify_css: opts.unminify_css, user_content_manager: state.user_content_manager, player_context: state.player_context, - node_ids: Default::default(), + pipeline_to_node_ids: Default::default(), is_user_interacting: Cell::new(false), #[cfg(feature = "webgpu")] gpu_id_hub: Arc::new(IdentityHub::default()), @@ -2266,15 +2280,6 @@ impl ScriptThread { can_gc, ) }, - WebDriverScriptCommand::FocusElement(element_id, reply) => { - webdriver_handlers::handle_focus_element( - &documents, - pipeline_id, - element_id, - reply, - can_gc, - ) - }, WebDriverScriptCommand::ElementClick(element_id, reply) => { webdriver_handlers::handle_element_click( &documents, @@ -2380,6 +2385,20 @@ impl ScriptThread { WebDriverScriptCommand::GetTitle(reply) => { webdriver_handlers::handle_get_title(&documents, pipeline_id, reply) }, + WebDriverScriptCommand::WillSendKeys( + element_id, + text, + strict_file_interactability, + reply, + ) => webdriver_handlers::handle_will_send_keys( + &documents, + pipeline_id, + element_id, + text, + strict_file_interactability, + reply, + can_gc, + ), _ => (), } } diff --git a/components/script/timers.rs b/components/script/timers.rs index 0dc1397fbdd..fe542c09a56 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -4,7 +4,7 @@ use std::cell::Cell; use std::cmp::{Ord, Ordering}; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::default::Default; use std::rc::Rc; use std::time::{Duration, Instant}; @@ -47,7 +47,7 @@ pub(crate) struct OneshotTimers { global_scope: Dom<GlobalScope>, js_timers: JsTimers, next_timer_handle: Cell<OneshotTimerHandle>, - timers: DomRefCell<Vec<OneshotTimer>>, + timers: DomRefCell<VecDeque<OneshotTimer>>, suspended_since: Cell<Option<Instant>>, /// Initially 0, increased whenever the associated document is reactivated /// by the amount of ms the document was inactive. The current time can be @@ -131,7 +131,7 @@ impl OneshotTimers { global_scope: Dom::from_ref(global_scope), js_timers: JsTimers::default(), next_timer_handle: Cell::new(OneshotTimerHandle(1)), - timers: DomRefCell::new(Vec::new()), + timers: DomRefCell::new(VecDeque::new()), suspended_since: Cell::new(None), suspension_offset: Cell::new(Duration::ZERO), expected_event_id: Cell::new(TimerEventId(0)), @@ -180,7 +180,7 @@ impl OneshotTimers { } fn is_next_timer(&self, handle: OneshotTimerHandle) -> bool { - match self.timers.borrow().last() { + match self.timers.borrow().back() { None => false, Some(max_timer) => max_timer.handle == handle, } @@ -201,7 +201,7 @@ impl OneshotTimers { let base_time = self.base_time(); // Since the event id was the expected one, at least one timer should be due. - if base_time < self.timers.borrow().last().unwrap().scheduled_for { + if base_time < self.timers.borrow().back().unwrap().scheduled_for { warn!("Unexpected timing!"); return; } @@ -213,11 +213,11 @@ impl OneshotTimers { loop { let mut timers = self.timers.borrow_mut(); - if timers.is_empty() || timers.last().unwrap().scheduled_for > base_time { + if timers.is_empty() || timers.back().unwrap().scheduled_for > base_time { break; } - timers_to_run.push(timers.pop().unwrap()); + timers_to_run.push(timers.pop_back().unwrap()); } for timer in timers_to_run { @@ -286,7 +286,7 @@ impl OneshotTimers { } let timers = self.timers.borrow(); - let Some(timer) = timers.last() else { + let Some(timer) = timers.back() else { return; }; diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 6b4264d945e..c81dcbd85fd 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -81,7 +81,7 @@ fn find_node_by_unique_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) { + if ScriptThread::has_node_id(pipeline, &node_id) { Err(ErrorStatus::StaleElementReference) } else { Err(ErrorStatus::NoSuchElement) @@ -94,14 +94,15 @@ pub(crate) fn find_node_by_unique_id_in_document( document: &Document, node_id: String, ) -> Result<DomRoot<Node>, ErrorStatus> { + let pipeline = document.window().pipeline_id(); match document .upcast::<Node>() .traverse_preorder(ShadowIncluding::Yes) - .find(|node| node.unique_id() == node_id) + .find(|node| node.unique_id(pipeline) == node_id) { Some(node) => Ok(node), None => { - if ScriptThread::has_node_id(&node_id) { + if ScriptThread::has_node_id(pipeline, &node_id) { Err(ErrorStatus::StaleElementReference) } else { Err(ErrorStatus::NoSuchElement) @@ -129,7 +130,10 @@ fn matching_links( content == link_text } }) - .map(|node| node.upcast::<Node>().unique_id()) + .map(|node| { + node.upcast::<Node>() + .unique_id(node.owner_doc().window().pipeline_id()) + }) } fn all_matching_links( @@ -329,20 +333,25 @@ 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( - element.upcast::<Node>().unique_id(), + element + .upcast::<Node>() + .unique_id(element.owner_document().window().pipeline_id()), ))) } else if let Ok(window) = root_from_object::<Window>(*object, cx) { let window_proxy = window.window_proxy(); if window_proxy.is_browsing_context_discarded() { 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(), - ))) } else { - Ok(WebDriverJSValue::Frame(WebFrame( - window.Document().upcast::<Node>().unique_id(), - ))) + let pipeline = window.pipeline_id(); + if window_proxy.browsing_context_id() == window_proxy.webview_id() { + Ok(WebDriverJSValue::Window(WebWindow( + window.Document().upcast::<Node>().unique_id(pipeline), + ))) + } else { + Ok(WebDriverJSValue::Frame(WebFrame( + window.Document().upcast::<Node>().unique_id(pipeline), + ))) + } } } else if object_has_to_json_property(cx, global_scope, object.handle()) { let name = CString::new("toJSON").unwrap(); @@ -598,7 +607,7 @@ pub(crate) fn handle_find_element_css( .QuerySelector(DOMString::from(selector)) .map_err(|_| ErrorStatus::InvalidSelector) }) - .map(|node| node.map(|x| x.upcast::<Node>().unique_id())), + .map(|node| node.map(|x| x.upcast::<Node>().unique_id(pipeline))), ) .unwrap(); } @@ -640,7 +649,7 @@ pub(crate) fn handle_find_element_tag_name( .elements_iter() .next() }) - .map(|node| node.map(|x| x.upcast::<Node>().unique_id())), + .map(|node| node.map(|x| x.upcast::<Node>().unique_id(pipeline))), ) .unwrap(); } @@ -664,7 +673,7 @@ pub(crate) fn handle_find_elements_css( .map(|nodes| { nodes .iter() - .map(|x| x.upcast::<Node>().unique_id()) + .map(|x| x.upcast::<Node>().unique_id(pipeline)) .collect() }), ) @@ -706,7 +715,7 @@ pub(crate) fn handle_find_elements_tag_name( .map(|nodes| { nodes .elements_iter() - .map(|x| x.upcast::<Node>().unique_id()) + .map(|x| x.upcast::<Node>().unique_id(pipeline)) .collect::<Vec<String>>() }), ) @@ -725,7 +734,7 @@ pub(crate) fn handle_find_element_element_css( find_node_by_unique_id(documents, pipeline, element_id).and_then(|node| { node.query_selector(DOMString::from(selector)) .map_err(|_| ErrorStatus::InvalidSelector) - .map(|node| node.map(|x| x.upcast::<Node>().unique_id())) + .map(|node| node.map(|x| x.upcast::<Node>().unique_id(pipeline))) }), ) .unwrap(); @@ -764,7 +773,7 @@ pub(crate) fn handle_find_element_element_tag_name( .GetElementsByTagName(DOMString::from(selector), can_gc) .elements_iter() .next() - .map(|x| x.upcast::<Node>().unique_id())), + .map(|x| x.upcast::<Node>().unique_id(pipeline))), None => Err(ErrorStatus::UnknownError), }), ) @@ -786,7 +795,7 @@ pub(crate) fn handle_find_element_elements_css( .map(|nodes| { nodes .iter() - .map(|x| x.upcast::<Node>().unique_id()) + .map(|x| x.upcast::<Node>().unique_id(pipeline)) .collect() }) }), @@ -826,7 +835,7 @@ pub(crate) fn handle_find_element_elements_tag_name( Some(element) => Ok(element .GetElementsByTagName(DOMString::from(selector), can_gc) .elements_iter() - .map(|x| x.upcast::<Node>().unique_id()) + .map(|x| x.upcast::<Node>().unique_id(pipeline)) .collect::<Vec<String>>()), None => Err(ErrorStatus::UnknownError), }), @@ -834,24 +843,66 @@ pub(crate) fn handle_find_element_elements_tag_name( .unwrap(); } -pub(crate) fn handle_focus_element( +pub(crate) fn handle_will_send_keys( documents: &DocumentCollection, pipeline: PipelineId, element_id: String, - reply: IpcSender<Result<(), ErrorStatus>>, + text: String, + strict_file_interactability: bool, + reply: IpcSender<Result<bool, ErrorStatus>>, can_gc: CanGc, ) { reply .send( find_node_by_unique_id(documents, pipeline, element_id).and_then(|node| { - match node.downcast::<HTMLElement>() { - Some(element) => { - // Need a way to find if this actually succeeded - element.Focus(can_gc); - Ok(()) - }, - None => Err(ErrorStatus::UnknownError), + // Step 6: Let file be true if element is input element + // in the file upload state, or false otherwise + let file_input = node + .downcast::<HTMLInputElement>() + .filter(|&input_element| input_element.input_type() == InputType::File); + + // Step 7: If file is false or the session's strict file interactability + if file_input.is_none() || strict_file_interactability { + match node.downcast::<HTMLElement>() { + Some(element) => { + // Need a way to find if this actually succeeded + element.Focus(can_gc); + }, + None => return Err(ErrorStatus::UnknownError), + } } + + // Step 8 (file input) + if let Some(file_input) = file_input { + // Step 8.1: Let files be the result of splitting text + // on the newline (\n) character. + let files: Vec<DOMString> = text.split("\n").map(|s| s.into()).collect(); + + // Step 8.2 + if files.is_empty() { + return Err(ErrorStatus::InvalidArgument); + } + + // Step 8.3 - 8.4 + if !file_input.Multiple() && files.len() > 1 { + return Err(ErrorStatus::InvalidArgument); + } + + // Step 8.5 + // TODO: Should return invalid argument error if file doesn't exist + + // Step 8.6 - 8.7 + // Input and change event already fired in `htmlinputelement.rs`. + file_input.SelectFiles(files, can_gc); + + // Step 8.8 + return Ok(false); + } + + // TODO: Check non-typeable form control + // TODO: Check content editable + + Ok(true) }), ) .unwrap(); @@ -867,7 +918,7 @@ pub(crate) fn handle_get_active_element( documents .find_document(pipeline) .and_then(|document| document.GetActiveElement()) - .map(|element| element.upcast::<Node>().unique_id()), + .map(|element| element.upcast::<Node>().unique_id(pipeline)), ) .unwrap(); } @@ -1395,7 +1446,7 @@ pub(crate) fn handle_element_click( Ok(None) }, - None => Ok(Some(node.unique_id())), + None => Ok(Some(node.unique_id(pipeline))), } }), ) diff --git a/components/script/xpath/context.rs b/components/script/xpath/context.rs index df78a9a7bec..ff51c92521d 100644 --- a/components/script/xpath/context.rs +++ b/components/script/xpath/context.rs @@ -5,10 +5,14 @@ use std::iter::Enumerate; use std::vec::IntoIter; +use script_bindings::str::DOMString; + use super::Node; +use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::root::DomRoot; /// The context during evaluation of an XPath expression. +#[derive(Debug)] pub(crate) struct EvaluationCtx { /// Where we started at pub(crate) starting_node: DomRoot<Node>, @@ -20,7 +24,7 @@ pub(crate) struct EvaluationCtx { pub(crate) predicate_nodes: Option<Vec<DomRoot<Node>>>, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(crate) struct PredicateCtx { pub(crate) index: usize, pub(crate) size: usize, @@ -68,6 +72,12 @@ impl EvaluationCtx { size, } } + + /// Resolve a namespace prefix using the context node's document + pub(crate) fn resolve_namespace(&self, prefix: Option<&str>) -> Option<DOMString> { + self.context_node + .LookupNamespaceURI(prefix.map(DOMString::from)) + } } /// When evaluating predicates, we need to keep track of the current node being evaluated and diff --git a/components/script/xpath/eval.rs b/components/script/xpath/eval.rs index 75d7ac5849c..38d8c2fee90 100644 --- a/components/script/xpath/eval.rs +++ b/components/script/xpath/eval.rs @@ -12,6 +12,7 @@ use super::parser::{ QName as ParserQualName, RelationalOp, StepExpr, UnaryOp, }; use super::{EvaluationCtx, Value}; +use crate::dom::attr::Attr; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId}; use crate::dom::bindings::root::DomRoot; @@ -83,6 +84,22 @@ where } } +impl<T> Evaluatable for Option<T> +where + T: Evaluatable, +{ + fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> { + match self { + Some(expr) => expr.evaluate(context), + None => Ok(Value::Nodeset(vec![])), + } + } + + fn is_primitive(&self) -> bool { + self.as_ref().is_some_and(|t| T::is_primitive(t)) + } +} + impl Evaluatable for Expr { fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> { match self { @@ -230,21 +247,31 @@ impl Evaluatable for PathExpr { } } -impl TryFrom<&ParserQualName> for QualName { +pub(crate) struct QualNameConverter<'a> { + qname: &'a ParserQualName, + context: &'a EvaluationCtx, +} + +impl<'a> TryFrom<QualNameConverter<'a>> for QualName { type Error = Error; - fn try_from(qname: &ParserQualName) -> Result<Self, Self::Error> { - let qname_as_str = qname.to_string(); - if let Ok((ns, prefix, local)) = validate_and_extract(None, &qname_as_str) { + fn try_from(converter: QualNameConverter<'a>) -> Result<Self, Self::Error> { + let qname_as_str = converter.qname.to_string(); + let namespace = converter + .context + .resolve_namespace(converter.qname.prefix.as_deref()); + + if let Ok((ns, prefix, local)) = validate_and_extract(namespace, &qname_as_str) { Ok(QualName { prefix, ns, local }) } else { Err(Error::InvalidQName { - qname: qname.clone(), + qname: converter.qname.clone(), }) } } } +#[derive(Debug)] pub(crate) enum NameTestComparisonMode { /// Namespaces must match exactly XHtml, @@ -294,29 +321,41 @@ pub(crate) fn element_name_test( } } -fn apply_node_test(test: &NodeTest, node: &Node) -> Result<bool, Error> { +fn apply_node_test(context: &EvaluationCtx, test: &NodeTest, node: &Node) -> Result<bool, Error> { let result = match test { NodeTest::Name(qname) => { // Convert the unvalidated "parser QualName" into the proper QualName structure - let wanted_name: QualName = qname.try_into()?; - if matches!(node.type_id(), NodeTypeId::Element(_)) { - let element = node.downcast::<Element>().unwrap(); - let comparison_mode = if node.owner_doc().is_xhtml_document() { - NameTestComparisonMode::XHtml - } else { - NameTestComparisonMode::Html - }; - let element_qualname = QualName::new( - element.prefix().as_ref().cloned(), - element.namespace().clone(), - element.local_name().clone(), - ); - element_name_test(wanted_name, element_qualname, comparison_mode) - } else { - false + let wanted_name: QualName = QualNameConverter { qname, context }.try_into()?; + match node.type_id() { + NodeTypeId::Element(_) => { + let element = node.downcast::<Element>().unwrap(); + let comparison_mode = if node.owner_doc().is_html_document() { + NameTestComparisonMode::Html + } else { + NameTestComparisonMode::XHtml + }; + let element_qualname = QualName::new( + element.prefix().as_ref().cloned(), + element.namespace().clone(), + element.local_name().clone(), + ); + element_name_test(wanted_name, element_qualname, comparison_mode) + }, + NodeTypeId::Attr => { + let attr = node.downcast::<Attr>().unwrap(); + let attr_qualname = QualName::new( + attr.prefix().cloned(), + attr.namespace().clone(), + attr.local_name().clone(), + ); + // attributes are always compared with strict namespace matching + let comparison_mode = NameTestComparisonMode::XHtml; + element_name_test(wanted_name, attr_qualname, comparison_mode) + }, + _ => false, } }, - NodeTest::Wildcard => true, + NodeTest::Wildcard => matches!(node.type_id(), NodeTypeId::Element(_)), NodeTest::Kind(kind) => match kind { KindTest::PI(target) => { if NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) == @@ -411,7 +450,7 @@ impl Evaluatable for StepExpr { let filtered_nodes: Vec<DomRoot<Node>> = nodes .into_iter() .map(|node| { - apply_node_test(&axis_step.node_test, &node) + apply_node_test(context, &axis_step.node_test, &node) .map(|matches| matches.then_some(node)) }) .collect::<Result<Vec<_>, _>>()? @@ -489,6 +528,7 @@ impl Evaluatable for PredicateExpr { let v = match eval_result { Ok(Value::Number(v)) => Ok(predicate_ctx.index == v as usize), + Ok(Value::Boolean(v)) => Ok(v), Ok(v) => Ok(v.boolean()), Err(e) => Err(e), }; diff --git a/components/script/xpath/eval_function.rs b/components/script/xpath/eval_function.rs index caf0782c07b..53c14944474 100644 --- a/components/script/xpath/eval_function.rs +++ b/components/script/xpath/eval_function.rs @@ -2,12 +2,15 @@ * 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 style::Atom; + use super::Value; use super::context::EvaluationCtx; use super::eval::{Error, Evaluatable, try_extract_nodeset}; use super::parser::CoreFunction; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::inheritance::{Castable, NodeTypeId}; +use crate::dom::bindings::root::DomRoot; use crate::dom::element::Element; use crate::dom::node::Node; @@ -101,6 +104,31 @@ pub(crate) fn normalize_space(s: &str) -> String { result } +/// <https://www.w3.org/TR/1999/REC-xpath-19991116/#function-lang> +fn lang_matches(context_lang: Option<&str>, target_lang: &str) -> bool { + let Some(context_lang) = context_lang else { + return false; + }; + + let context_lower = context_lang.to_ascii_lowercase(); + let target_lower = target_lang.to_ascii_lowercase(); + + if context_lower == target_lower { + return true; + } + + // Check if context is target with additional suffix + if context_lower.starts_with(&target_lower) { + // Make sure the next character is a hyphen to avoid matching + // e.g. "england" when target is "en" + if let Some(next_char) = context_lower.chars().nth(target_lower.len()) { + return next_char == '-'; + } + } + + false +} + impl Evaluatable for CoreFunction { fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> { match self { @@ -131,7 +159,20 @@ impl Evaluatable for CoreFunction { .collect(); Ok(Value::String(strings?.join(""))) }, - CoreFunction::Id(_expr) => todo!(), + CoreFunction::Id(expr) => { + let args_str = expr.evaluate(context)?.string(); + let args_normalized = normalize_space(&args_str); + let args = args_normalized.split(' '); + + let document = context.context_node.owner_doc(); + let mut result = Vec::new(); + for arg in args { + for element in document.get_elements_with_id(&Atom::from(arg)).iter() { + result.push(DomRoot::from_ref(element.upcast::<Node>())); + } + } + Ok(Value::Nodeset(result)) + }, CoreFunction::LocalName(expr_opt) => { let node = match expr_opt { Some(expr) => expr @@ -256,7 +297,11 @@ impl Evaluatable for CoreFunction { CoreFunction::Not(expr) => Ok(Value::Boolean(!expr.evaluate(context)?.boolean())), CoreFunction::True => Ok(Value::Boolean(true)), CoreFunction::False => Ok(Value::Boolean(false)), - CoreFunction::Lang(_) => Ok(Value::Nodeset(vec![])), // Not commonly used in the DOM, short-circuit it + CoreFunction::Lang(expr) => { + let context_lang = context.context_node.get_lang(); + let lang = expr.evaluate(context)?.string(); + Ok(Value::Boolean(lang_matches(context_lang.as_deref(), &lang))) + }, } } @@ -319,7 +364,7 @@ impl Evaluatable for CoreFunction { } #[cfg(test)] mod tests { - use super::{substring, substring_after, substring_before}; + use super::{lang_matches, substring, substring_after, substring_before}; #[test] fn test_substring_before() { @@ -354,4 +399,18 @@ mod tests { assert_eq!(substring("hello", 0, Some(0)), ""); assert_eq!(substring("hello", 0, Some(-5)), ""); } + + #[test] + fn test_lang_matches() { + assert!(lang_matches(Some("en"), "en")); + assert!(lang_matches(Some("EN"), "en")); + assert!(lang_matches(Some("en"), "EN")); + assert!(lang_matches(Some("en-US"), "en")); + assert!(lang_matches(Some("en-GB"), "en")); + + assert!(!lang_matches(Some("eng"), "en")); + assert!(!lang_matches(Some("fr"), "en")); + assert!(!lang_matches(Some("fr-en"), "en")); + assert!(!lang_matches(None, "en")); + } } diff --git a/components/script/xpath/eval_value.rs b/components/script/xpath/eval_value.rs index de6c13e3454..66f1b92c6d4 100644 --- a/components/script/xpath/eval_value.rs +++ b/components/script/xpath/eval_value.rs @@ -8,7 +8,6 @@ use std::{fmt, string}; use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::utils::AsVoidPtr; use crate::dom::node::Node; /// The primary types of values that an XPath expression returns as a result. @@ -216,7 +215,7 @@ impl NodesetHelpers for Vec<DomRoot<Node>> { } fn document_order(&self) -> Vec<DomRoot<Node>> { let mut nodes: Vec<DomRoot<Node>> = self.clone(); - if nodes.len() == 1 { + if nodes.len() <= 1 { return nodes; } @@ -233,10 +232,13 @@ impl NodesetHelpers for Vec<DomRoot<Node>> { nodes } fn document_order_unique(&self) -> Vec<DomRoot<Node>> { - let mut nodes: Vec<DomRoot<Node>> = self.document_order(); - - nodes.dedup_by_key(|n| n.as_void_ptr()); + let mut seen = HashSet::new(); + let unique_nodes: Vec<DomRoot<Node>> = self + .iter() + .filter(|node| seen.insert(node.to_opaque())) + .cloned() + .collect(); - nodes + unique_nodes.document_order() } } diff --git a/components/script/xpath/parser.rs b/components/script/xpath/parser.rs index b1a4bfcc42d..272fa41dcdf 100644 --- a/components/script/xpath/parser.rs +++ b/components/script/xpath/parser.rs @@ -510,40 +510,45 @@ fn union_expr(input: &str) -> IResult<&str, Expr> { fn path_expr(input: &str) -> IResult<&str, Expr> { alt(( // "//" RelativePathExpr - map(pair(tag("//"), relative_path_expr), |(_, rel_path)| { - Expr::Path(PathExpr { - is_absolute: true, - is_descendant: true, - steps: match rel_path { - Expr::Path(p) => p.steps, - _ => unreachable!(), - }, - }) - }), - // "/" RelativePathExpr? - map(pair(char('/'), opt(relative_path_expr)), |(_, rel_path)| { - Expr::Path(PathExpr { - is_absolute: true, - is_descendant: false, - steps: rel_path - .map(|p| match p { + map( + pair(tag("//"), move |i| relative_path_expr(true, i)), + |(_, rel_path)| { + Expr::Path(PathExpr { + is_absolute: true, + is_descendant: true, + steps: match rel_path { Expr::Path(p) => p.steps, _ => unreachable!(), - }) - .unwrap_or_default(), - }) - }), + }, + }) + }, + ), + // "/" RelativePathExpr? + map( + pair(char('/'), opt(move |i| relative_path_expr(false, i))), + |(_, rel_path)| { + Expr::Path(PathExpr { + is_absolute: true, + is_descendant: false, + steps: rel_path + .map(|p| match p { + Expr::Path(p) => p.steps, + _ => unreachable!(), + }) + .unwrap_or_default(), + }) + }, + ), // RelativePathExpr - relative_path_expr, + move |i| relative_path_expr(false, i), ))(input) } -fn relative_path_expr(input: &str) -> IResult<&str, Expr> { - let (input, first) = step_expr(input)?; +fn relative_path_expr(is_descendant: bool, input: &str) -> IResult<&str, Expr> { + let (input, first) = step_expr(is_descendant, input)?; let (input, steps) = many0(pair( - // ("/" | "//") - ws(alt((value(false, char('/')), value(true, tag("//"))))), - step_expr, + ws(alt((value(true, tag("//")), value(false, char('/'))))), + move |i| step_expr(is_descendant, i), ))(input)?; let mut all_steps = vec![first]; @@ -569,16 +574,18 @@ fn relative_path_expr(input: &str) -> IResult<&str, Expr> { )) } -fn step_expr(input: &str) -> IResult<&str, StepExpr> { +fn step_expr(is_descendant: bool, input: &str) -> IResult<&str, StepExpr> { alt(( map(filter_expr, StepExpr::Filter), - map(axis_step, StepExpr::Axis), + map(|i| axis_step(is_descendant, i), StepExpr::Axis), ))(input) } -fn axis_step(input: &str) -> IResult<&str, AxisStep> { - let (input, (step, predicates)) = - pair(alt((forward_step, reverse_step)), predicate_list)(input)?; +fn axis_step(is_descendant: bool, input: &str) -> IResult<&str, AxisStep> { + let (input, (step, predicates)) = pair( + alt((move |i| forward_step(is_descendant, i), reverse_step)), + predicate_list, + )(input)?; let (axis, node_test) = step; Ok(( @@ -591,13 +598,10 @@ fn axis_step(input: &str) -> IResult<&str, AxisStep> { )) } -fn forward_step(input: &str) -> IResult<&str, (Axis, NodeTest)> { - alt(( - // ForwardAxis NodeTest - pair(forward_axis, node_test), - // AbbrevForwardStep - abbrev_forward_step, - ))(input) +fn forward_step(is_descendant: bool, input: &str) -> IResult<&str, (Axis, NodeTest)> { + alt((pair(forward_axis, node_test), move |i| { + abbrev_forward_step(is_descendant, i) + }))(input) } fn forward_axis(input: &str) -> IResult<&str, Axis> { @@ -615,7 +619,7 @@ fn forward_axis(input: &str) -> IResult<&str, Axis> { Ok((input, axis)) } -fn abbrev_forward_step(input: &str) -> IResult<&str, (Axis, NodeTest)> { +fn abbrev_forward_step(is_descendant: bool, input: &str) -> IResult<&str, (Axis, NodeTest)> { let (input, attr) = opt(char('@'))(input)?; let (input, test) = node_test(input)?; @@ -624,6 +628,8 @@ fn abbrev_forward_step(input: &str) -> IResult<&str, (Axis, NodeTest)> { ( if attr.is_some() { Axis::Attribute + } else if is_descendant { + Axis::DescendantOrSelf } else { Axis::Child }, @@ -704,6 +710,7 @@ fn filter_expr(input: &str) -> IResult<&str, FilterExpr> { fn predicate_list(input: &str) -> IResult<&str, PredicateListExpr> { let (input, predicates) = many0(predicate)(input)?; + Ok((input, PredicateListExpr { predicates })) } @@ -1195,6 +1202,118 @@ mod tests { ], }), ), + ( + "//mu[@xml:id=\"id1\"]//rho[@title][@xml:lang=\"en-GB\"]", + Expr::Path(PathExpr { + is_absolute: true, + is_descendant: true, + steps: vec![ + StepExpr::Axis(AxisStep { + axis: Axis::Child, + node_test: NodeTest::Name(QName { + prefix: None, + local_part: "mu".to_string(), + }), + predicates: PredicateListExpr { + predicates: vec![PredicateExpr { + expr: Expr::Equality( + Box::new(Expr::Path(PathExpr { + is_absolute: false, + is_descendant: false, + steps: vec![StepExpr::Axis(AxisStep { + axis: Axis::Attribute, + node_test: NodeTest::Name(QName { + prefix: Some("xml".to_string()), + local_part: "id".to_string(), + }), + predicates: PredicateListExpr { + predicates: vec![], + }, + })], + })), + EqualityOp::Eq, + Box::new(Expr::Path(PathExpr { + is_absolute: false, + is_descendant: false, + steps: vec![StepExpr::Filter(FilterExpr { + primary: PrimaryExpr::Literal(Literal::String( + "id1".to_string(), + )), + predicates: PredicateListExpr { + predicates: vec![], + }, + })], + })), + ), + }], + }, + }), + StepExpr::Axis(AxisStep { + axis: Axis::DescendantOrSelf, // Represents the second '//' + node_test: NodeTest::Kind(KindTest::Node), + predicates: PredicateListExpr { predicates: vec![] }, + }), + StepExpr::Axis(AxisStep { + axis: Axis::Child, + node_test: NodeTest::Name(QName { + prefix: None, + local_part: "rho".to_string(), + }), + predicates: PredicateListExpr { + predicates: vec![ + PredicateExpr { + expr: Expr::Path(PathExpr { + is_absolute: false, + is_descendant: false, + steps: vec![StepExpr::Axis(AxisStep { + axis: Axis::Attribute, + node_test: NodeTest::Name(QName { + prefix: None, + local_part: "title".to_string(), + }), + predicates: PredicateListExpr { + predicates: vec![], + }, + })], + }), + }, + PredicateExpr { + expr: Expr::Equality( + Box::new(Expr::Path(PathExpr { + is_absolute: false, + is_descendant: false, + steps: vec![StepExpr::Axis(AxisStep { + axis: Axis::Attribute, + node_test: NodeTest::Name(QName { + prefix: Some("xml".to_string()), + local_part: "lang".to_string(), + }), + predicates: PredicateListExpr { + predicates: vec![], + }, + })], + })), + EqualityOp::Eq, + Box::new(Expr::Path(PathExpr { + is_absolute: false, + is_descendant: false, + steps: vec![StepExpr::Filter(FilterExpr { + primary: PrimaryExpr::Literal(Literal::String( + "en-GB".to_string(), + )), + predicates: PredicateListExpr { + predicates: vec![], + }, + })], + })), + ), + }, + ], + }, + }), + ], + }), + ), ]; for (input, expected) in cases { diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 7cc092e574e..dd034654974 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -14,6 +14,10 @@ DOMInterfaces = { +'AbortController': { + 'canGc':['Abort'], +}, + 'AbstractRange': { 'weakReferenceable': True, }, diff --git a/components/script_bindings/webidls/AbortController.webidl b/components/script_bindings/webidls/AbortController.webidl index cef49010d3c..bb20ec24955 100644 --- a/components/script_bindings/webidls/AbortController.webidl +++ b/components/script_bindings/webidls/AbortController.webidl @@ -7,7 +7,7 @@ interface AbortController { constructor(); - //[SameObject] readonly attribute AbortSignal signal; + [SameObject] readonly attribute AbortSignal signal; undefined abort(optional any reason); }; diff --git a/components/script_bindings/webidls/HTMLHRElement.webidl b/components/script_bindings/webidls/HTMLHRElement.webidl index 8963d5e8901..45828d4da76 100644 --- a/components/script_bindings/webidls/HTMLHRElement.webidl +++ b/components/script_bindings/webidls/HTMLHRElement.webidl @@ -12,14 +12,9 @@ interface HTMLHRElement : HTMLElement { // https://html.spec.whatwg.org/multipage/#HTMLHRElement-partial partial interface HTMLHRElement { - [CEReactions] - attribute DOMString align; - [CEReactions] - attribute DOMString color; - // [CEReactions] - // attribute boolean noShade; - // [CEReactions] - // attribute DOMString size; - [CEReactions] - attribute DOMString width; + [CEReactions] attribute DOMString align; + [CEReactions] attribute DOMString color; + [CEReactions] attribute boolean noShade; + [CEReactions] attribute DOMString size; + [CEReactions] attribute DOMString width; }; diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs index 869c4eee004..ff48bd7b7d8 100644 --- a/components/shared/embedder/input_events.rs +++ b/components/shared/embedder/input_events.rs @@ -58,16 +58,16 @@ impl InputEvent { } } - pub fn with_webdriver_message_id(self, webdriver_id: Option<WebDriverMessageId>) -> Self { + pub fn with_webdriver_message_id(mut self, webdriver_id: Option<WebDriverMessageId>) -> Self { match self { InputEvent::EditingAction(..) => {}, InputEvent::Gamepad(..) => {}, InputEvent::Ime(..) => {}, InputEvent::Keyboard(..) => {}, - InputEvent::MouseButton(mut event) => { + InputEvent::MouseButton(ref mut event) => { event.webdriver_id = webdriver_id; }, - InputEvent::MouseMove(mut event) => { + InputEvent::MouseMove(ref mut event) => { event.webdriver_id = webdriver_id; }, InputEvent::Touch(..) => {}, diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs index 7b0f02bc26a..ad1271a045c 100644 --- a/components/shared/embedder/webdriver.rs +++ b/components/shared/embedder/webdriver.rs @@ -130,7 +130,6 @@ pub enum WebDriverScriptCommand { IpcSender<Result<Vec<String>, ErrorStatus>>, ), FindElementElementsTagName(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>), - FocusElement(String, IpcSender<Result<(), ErrorStatus>>), ElementClick(String, IpcSender<Result<Option<String>, ErrorStatus>>), GetActiveElement(IpcSender<Option<String>>), GetComputedRole(String, IpcSender<Result<Option<String>, ErrorStatus>>), @@ -161,6 +160,8 @@ pub enum WebDriverScriptCommand { IsEnabled(String, IpcSender<Result<bool, ErrorStatus>>), IsSelected(String, IpcSender<Result<bool, ErrorStatus>>), GetTitle(IpcSender<String>), + /// Match the element type before sending the event for webdriver `element send keys`. + WillSendKeys(String, String, bool, IpcSender<Result<bool, ErrorStatus>>), } #[derive(Debug, Deserialize, Serialize)] diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index f33310ac001..b84cbb4c2f8 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; +use std::thread; use std::time::{Duration, Instant}; -use std::{cmp, thread}; use constellation_traits::EmbedderToConstellationMessage; use embedder_traits::{MouseButtonAction, WebDriverCommandMsg, WebDriverScriptCommand}; @@ -12,10 +12,11 @@ use ipc_channel::ipc; use keyboard_types::webdriver::KeyInputState; use webdriver::actions::{ ActionSequence, ActionsType, GeneralAction, KeyAction, KeyActionItem, KeyDownAction, - KeyUpAction, NullActionItem, PointerAction, PointerActionItem, PointerActionParameters, - PointerDownAction, PointerMoveAction, PointerOrigin, PointerType, PointerUpAction, WheelAction, - WheelActionItem, WheelScrollAction, + KeyUpAction, NullActionItem, PointerAction, PointerActionItem, PointerDownAction, + PointerMoveAction, PointerOrigin, PointerType, PointerUpAction, WheelAction, WheelActionItem, + WheelScrollAction, }; +use webdriver::command::ActionsParameters; use webdriver::error::{ErrorStatus, WebDriverError}; use crate::{Handler, WebElement, wait_for_script_response}; @@ -24,11 +25,32 @@ use crate::{Handler, WebElement, wait_for_script_response}; static POINTERMOVE_INTERVAL: u64 = 17; static WHEELSCROLL_INTERVAL: u64 = 17; -// https://w3c.github.io/webdriver/#dfn-input-source-state +// A single action, corresponding to an `action object` in the spec. +// In the spec, `action item` refers to a plain JSON object. +// However, we use the name ActionItem here +// to be consistent with type names from webdriver crate. +pub(crate) enum ActionItem { + Null(NullActionItem), + Key(KeyActionItem), + Pointer(PointerActionItem), + Wheel(WheelActionItem), +} + +// A set of actions with multiple sources executed within a single tick. +// The order in which they are performed is not guaranteed. +// The `id` is used to identify the source of the actions. +pub(crate) type TickActions = HashMap<String, ActionItem>; + +// Consumed by the `dispatch_actions` method. +pub(crate) type ActionsByTick = Vec<TickActions>; + +/// <https://w3c.github.io/webdriver/#dfn-input-source-state> pub(crate) enum InputSourceState { Null, + #[allow(dead_code)] Key(KeyInputState), Pointer(PointerInputState), + #[allow(dead_code)] Wheel, } @@ -44,13 +66,9 @@ pub(crate) struct PointerInputState { } impl PointerInputState { - pub fn new(subtype: &PointerType) -> PointerInputState { + pub fn new(subtype: PointerType) -> PointerInputState { PointerInputState { - subtype: match subtype { - PointerType::Mouse => PointerType::Mouse, - PointerType::Pen => PointerType::Pen, - PointerType::Touch => PointerType::Touch, - }, + subtype, pressed: HashSet::new(), x: 0.0, y: 0.0, @@ -58,48 +76,44 @@ impl PointerInputState { } } -// https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration -fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 { - let mut duration = 0; - match &tick_actions.actions { - ActionsType::Null { actions } => { - for action in actions.iter() { - let NullActionItem::General(GeneralAction::Pause(pause_action)) = action; - duration = cmp::max(duration, pause_action.duration.unwrap_or(0)); - } - }, - ActionsType::Pointer { - parameters: _, - actions, - } => { - for action in actions.iter() { - let action_duration = match action { - PointerActionItem::General(GeneralAction::Pause(action)) => action.duration, - PointerActionItem::Pointer(PointerAction::Move(action)) => action.duration, - _ => None, - }; - duration = cmp::max(duration, action_duration.unwrap_or(0)); - } - }, - ActionsType::Key { actions: _ } => (), - 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)); +/// <https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration> +fn compute_tick_duration(tick_actions: &TickActions) -> u64 { + // Step 1. Let max duration be 0. + // Step 2. For each action in tick actions: + tick_actions + .iter() + .filter_map(|(_, action_item)| { + // If action object has subtype property set to "pause" or + // action object has type property set to "pointer" and subtype property set to "pointerMove", + // or action object has type property set to "wheel" and subtype property set to "scroll", + // let duration be equal to the duration property of action object. + match action_item { + ActionItem::Null(NullActionItem::General(GeneralAction::Pause(pause_action))) | + ActionItem::Key(KeyActionItem::General(GeneralAction::Pause(pause_action))) | + ActionItem::Pointer(PointerActionItem::General(GeneralAction::Pause( + pause_action, + ))) | + ActionItem::Wheel(WheelActionItem::General(GeneralAction::Pause(pause_action))) => { + pause_action.duration + }, + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Move(action))) => { + action.duration + }, + ActionItem::Wheel(WheelActionItem::Wheel(WheelAction::Scroll(action))) => { + action.duration + }, + _ => None, } - }, - } - duration + }) + .max() + .unwrap_or(0) } impl Handler { - // https://w3c.github.io/webdriver/#dfn-dispatch-actions + /// <https://w3c.github.io/webdriver/#dfn-dispatch-actions> pub(crate) fn dispatch_actions( &self, - actions_by_tick: &[ActionSequence], + actions_by_tick: ActionsByTick, ) -> Result<(), ErrorStatus> { // Step 1. Wait for an action queue token with input state. let new_token = self.id_generator.next(); @@ -116,11 +130,8 @@ impl Handler { res } - // https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner - fn dispatch_actions_inner( - &self, - actions_by_tick: &[ActionSequence], - ) -> Result<(), ErrorStatus> { + /// <https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner> + fn dispatch_actions_inner(&self, actions_by_tick: ActionsByTick) -> Result<(), ErrorStatus> { // Step 1. For each item tick actions in actions by tick for tick_actions in actions_by_tick.iter() { // Step 1.2. Let tick duration be the result of @@ -133,19 +144,33 @@ impl Handler { // Step 1.4. Wait for // The user agent event loop has spun enough times to process the DOM events // generated by the last invocation of the dispatch tick actions steps. - // - // To ensure we wait for all events to be processed, only the last event in - // this tick action step holds the message id. - // Whenever a new event is generated, the message id is passed to it. - // - // TO-DO: remove the first match after webdriver_id is implemented in all commands - match tick_actions.actions { - ActionsType::Key { .. } | ActionsType::Wheel { .. } | ActionsType::Null { .. } => { - return Ok(()); - }, - _ => {}, - } + self.wait_for_user_agent_handling_complete(tick_actions)?; + } + // Step 2. Return success with data null. + dbg!("Dispatch actions completed successfully"); + Ok(()) + } + + fn wait_for_user_agent_handling_complete( + &self, + tick_actions: &TickActions, + ) -> Result<(), ErrorStatus> { + // TODO: Add matches! for wheel and key actions + // after implmenting webdriver id for wheel and key events. + let count_non_null_actions_in_tick = tick_actions + .iter() + .filter(|(_, action)| { + matches!(action, ActionItem::Pointer(PointerActionItem::Pointer(_))) + }) + .count(); + + // To ensure we wait for all events to be processed, only the last event + // in each tick action step holds the message id. + // Whenever a new event is generated, the message id is passed to it. + // + // Wait for count_non_null_actions_in_tick number of responses + for _ in 0..count_non_null_actions_in_tick { match self.constellation_receiver.recv() { Ok(response) => { let current_waiting_id = self @@ -165,8 +190,86 @@ impl Handler { }; } - // Step 2. Return success with data null. - dbg!("Dispatch actions completed successfully"); + Ok(()) + } + + /// <https://w3c.github.io/webdriver/#dfn-dispatch-tick-actions> + fn dispatch_tick_actions( + &self, + tick_actions: &TickActions, + tick_duration: u64, + ) -> Result<(), ErrorStatus> { + // Step 1. For each action object in tick actions: + // Step 1.1. Let input_id be the value of the id property of action object. + for (input_id, action) in tick_actions.iter() { + // Step 6. Let subtype be action object's subtype. + // Steps 7, 8. Try to run specific algorithm based on the action type. + match action { + ActionItem::Null(NullActionItem::General(_)) => { + self.dispatch_general_action(input_id); + }, + ActionItem::Key(KeyActionItem::General(_)) => { + self.dispatch_general_action(input_id); + }, + ActionItem::Key(KeyActionItem::Key(KeyAction::Down(keydown_action))) => { + self.dispatch_keydown_action(input_id, keydown_action); + + // Step 9. If subtype is "keyDown", append a copy of action + // object with the subtype property changed to "keyUp" to + // input state's input cancel list. + self.session() + .unwrap() + .input_cancel_list + .borrow_mut() + .push(ActionItem::Key(KeyActionItem::Key(KeyAction::Up( + KeyUpAction { + value: keydown_action.value.clone(), + }, + )))); + }, + ActionItem::Key(KeyActionItem::Key(KeyAction::Up(keyup_action))) => { + self.dispatch_keyup_action(input_id, keyup_action); + }, + ActionItem::Pointer(PointerActionItem::General(_)) => { + self.dispatch_general_action(input_id); + }, + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Down( + pointer_down_action, + ))) => { + self.dispatch_pointerdown_action(input_id, pointer_down_action); + + // Step 10. If subtype is "pointerDown", append a copy of action + // object with the subtype property changed to "pointerUp" to + // input state's input cancel list. + self.session().unwrap().input_cancel_list.borrow_mut().push( + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Up( + PointerUpAction { + button: pointer_down_action.button, + ..Default::default() + }, + ))), + ); + }, + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Move( + pointer_move_action, + ))) => { + self.dispatch_pointermove_action(input_id, pointer_move_action, tick_duration)?; + }, + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Up( + pointer_up_action, + ))) => { + self.dispatch_pointerup_action(input_id, pointer_up_action); + }, + ActionItem::Wheel(WheelActionItem::General(_)) => { + self.dispatch_general_action(input_id); + }, + ActionItem::Wheel(WheelActionItem::Wheel(WheelAction::Scroll(scroll_action))) => { + self.dispatch_scroll_action(scroll_action, tick_duration)?; + }, + _ => {}, + } + } + Ok(()) } @@ -181,143 +284,7 @@ impl Handler { // Nothing to be done } - // https://w3c.github.io/webdriver/#dfn-dispatch-tick-actions - fn dispatch_tick_actions( - &self, - tick_actions: &ActionSequence, - tick_duration: u64, - ) -> Result<(), ErrorStatus> { - let source_id = &tick_actions.id; - match &tick_actions.actions { - ActionsType::Null { actions } => { - for _action in actions.iter() { - self.dispatch_general_action(source_id); - } - }, - ActionsType::Key { actions } => { - for action in actions.iter() { - match action { - KeyActionItem::General(_action) => { - self.dispatch_general_action(source_id); - }, - KeyActionItem::Key(action) => { - self.session() - .unwrap() - .input_state_table - .borrow_mut() - .entry(source_id.to_string()) - .or_insert(InputSourceState::Key(KeyInputState::new())); - match action { - KeyAction::Down(action) => { - self.dispatch_keydown_action(source_id, action); - // Step 9. If subtype is "keyDown", append a copy of action - // object with the subtype property changed to "keyUp" to - // input state's input cancel list. - self.session().unwrap().input_cancel_list.borrow_mut().push( - ActionSequence { - id: source_id.into(), - actions: ActionsType::Key { - actions: vec![KeyActionItem::Key(KeyAction::Up( - KeyUpAction { - value: action.value.clone(), - }, - ))], - }, - }, - ); - }, - KeyAction::Up(action) => { - self.dispatch_keyup_action(source_id, action) - }, - }; - }, - } - } - }, - ActionsType::Pointer { - parameters, - actions, - } => { - for action in actions.iter() { - match action { - PointerActionItem::General(_action) => { - self.dispatch_general_action(source_id); - }, - PointerActionItem::Pointer(action) => { - self.session() - .unwrap() - .input_state_table - .borrow_mut() - .entry(source_id.to_string()) - .or_insert(InputSourceState::Pointer(PointerInputState::new( - ¶meters.pointer_type, - ))); - match action { - PointerAction::Cancel => (), - PointerAction::Down(action) => { - self.dispatch_pointerdown_action(source_id, action); - - // Step 10. If subtype is "pointerDown", append a copy of action - // object with the subtype property changed to "pointerUp" to - // input state's input cancel list. - self.session().unwrap().input_cancel_list.borrow_mut().push( - ActionSequence { - id: source_id.into(), - actions: ActionsType::Pointer { - parameters: PointerActionParameters { - pointer_type: parameters.pointer_type, - }, - actions: vec![PointerActionItem::Pointer( - PointerAction::Up(PointerUpAction { - button: action.button, - ..Default::default() - }), - )], - }, - }, - ); - }, - PointerAction::Move(action) => self.dispatch_pointermove_action( - source_id, - action, - tick_duration, - )?, - PointerAction::Up(action) => { - self.dispatch_pointerup_action(source_id, action) - }, - } - }, - } - } - }, - ActionsType::Wheel { actions } => { - for action in actions.iter() { - match action { - WheelActionItem::General(_action) => { - self.dispatch_general_action(source_id) - }, - WheelActionItem::Wheel(action) => { - self.session() - .unwrap() - .input_state_table - .borrow_mut() - .entry(source_id.to_string()) - .or_insert(InputSourceState::Wheel); - match action { - WheelAction::Scroll(action) => { - self.dispatch_scroll_action(action, tick_duration)? - }, - } - }, - } - } - }, - } - - Ok(()) - } - - // https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action + /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action> fn dispatch_keydown_action(&self, source_id: &str, action: &KeyDownAction) { let session = self.session().unwrap(); @@ -340,7 +307,7 @@ impl Handler { .unwrap(); } - // https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action + /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action> fn dispatch_keyup_action(&self, source_id: &str, action: &KeyUpAction) { let session = self.session().unwrap(); @@ -393,7 +360,7 @@ impl Handler { .unwrap(); } - // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action + /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerup-action> pub(crate) fn dispatch_pointerup_action(&self, source_id: &str, action: &PointerUpAction) { let session = self.session().unwrap(); @@ -423,7 +390,7 @@ impl Handler { .unwrap(); } - // https://w3c.github.io/webdriver/#dfn-dispatch-a-pointermove-action + /// <https://w3c.github.io/webdriver/#dfn-dispatch-a-pointermove-action> pub(crate) fn dispatch_pointermove_action( &self, source_id: &str, @@ -738,4 +705,94 @@ impl Handler { None => Err(ErrorStatus::UnknownError), } } + + /// <https://w3c.github.io/webdriver/#dfn-extract-an-action-sequence> + pub(crate) fn extract_an_action_sequence(&self, params: ActionsParameters) -> ActionsByTick { + // Step 1. Let actions be the result of getting a property named "actions" from parameters. + // Step 2 (ignored because params is already validated earlier). If actions is not a list, + // return an error with status InvalidArgument. + let actions = params.actions; + + self.actions_by_tick_from_sequence(actions) + } + + pub(crate) fn actions_by_tick_from_sequence( + &self, + actions: Vec<ActionSequence>, + ) -> ActionsByTick { + // Step 3. Let actions by tick be an empty list. + let mut actions_by_tick: ActionsByTick = Vec::new(); + + // Step 4. For each value action sequence corresponding to an indexed property in actions + for action_sequence in actions { + // Store id before moving action_sequence + let id = action_sequence.id.clone(); + // Step 4.1. Let source actions be the result of trying to process an input source action sequence + let source_actions = self.process_an_input_source_action_sequence(action_sequence); + + // Step 4.2.2. Ensure we have enough ticks to hold all actions + while actions_by_tick.len() < source_actions.len() { + actions_by_tick.push(HashMap::new()); + } + + // Step 4.2.3. + for (tick_index, action_item) in source_actions.into_iter().enumerate() { + actions_by_tick[tick_index].insert(id.clone(), action_item); + } + } + + actions_by_tick + } + + /// <https://w3c.github.io/webdriver/#dfn-process-an-input-source-action-sequence> + pub(crate) fn process_an_input_source_action_sequence( + &self, + action_sequence: ActionSequence, + ) -> Vec<ActionItem> { + // Step 2. Let id be the value of the id property of action sequence. + let id = action_sequence.id.clone(); + + let mut input_state_table = self.session().unwrap().input_state_table.borrow_mut(); + + match action_sequence.actions { + ActionsType::Null { + actions: null_actions, + } => { + input_state_table + .entry(id) + .or_insert(InputSourceState::Null); + null_actions.into_iter().map(ActionItem::Null).collect() + }, + ActionsType::Key { + actions: key_actions, + } => { + input_state_table + .entry(id) + .or_insert(InputSourceState::Key(KeyInputState::new())); + key_actions.into_iter().map(ActionItem::Key).collect() + }, + ActionsType::Pointer { + parameters: _, + actions: pointer_actions, + } => { + input_state_table + .entry(id) + .or_insert(InputSourceState::Pointer(PointerInputState::new( + PointerType::Mouse, + ))); + pointer_actions + .into_iter() + .map(ActionItem::Pointer) + .collect() + }, + ActionsType::Wheel { + actions: wheel_actions, + } => { + input_state_table + .entry(id) + .or_insert(InputSourceState::Wheel); + wheel_actions.into_iter().map(ActionItem::Wheel).collect() + }, + } + } } diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index eb3e7bf17ec..1b585319703 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -64,7 +64,7 @@ use webdriver::response::{ }; use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler}; -use crate::actions::{InputSourceState, PointerInputState}; +use crate::actions::{ActionItem, InputSourceState, PointerInputState}; #[derive(Default)] pub struct WebDriverMessageIdGenerator { @@ -171,7 +171,7 @@ pub struct WebDriverSession { input_state_table: RefCell<HashMap<String, InputSourceState>>, /// <https://w3c.github.io/webdriver/#dfn-input-cancel-list> - input_cancel_list: RefCell<Vec<ActionSequence>>, + input_cancel_list: RefCell<Vec<ActionItem>>, } impl WebDriverSession { @@ -1480,20 +1480,22 @@ impl Handler { fn handle_perform_actions( &mut self, - parameters: &ActionsParameters, + parameters: ActionsParameters, ) -> WebDriverResult<WebDriverResponse> { - match self.dispatch_actions(¶meters.actions) { + // Step 5. Let actions by tick be the result of trying to extract an action sequence + let actions_by_tick = self.extract_an_action_sequence(parameters); + + // Step 6. Dispatch actions + match self.dispatch_actions(actions_by_tick) { Ok(_) => Ok(WebDriverResponse::Void), Err(error) => Err(WebDriverError::new(error, "")), } } + /// <https://w3c.github.io/webdriver/#dfn-release-actions> fn handle_release_actions(&mut self) -> WebDriverResult<WebDriverResponse> { - let input_cancel_list = self.session().unwrap().input_cancel_list.borrow(); - if let Err(error) = self.dispatch_actions(&input_cancel_list) { - return Err(WebDriverError::new(error, "")); - } - + // TODO: The previous implementation of this function was different from the spec. + // Need to re-implement this to match the spec. let session = self.session()?; session.input_state_table.borrow_mut().clear(); @@ -1617,14 +1619,23 @@ impl Handler { let (sender, receiver) = ipc::channel().unwrap(); - let cmd = WebDriverScriptCommand::FocusElement(element.to_string(), sender); + let cmd = WebDriverScriptCommand::WillSendKeys( + element.to_string(), + keys.text.to_string(), + self.session()?.strict_file_interactability, + sender, + ); let cmd_msg = WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd); self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) .unwrap(); // TODO: distinguish the not found and not focusable cases - wait_for_script_response(receiver)?.map_err(|error| WebDriverError::new(error, ""))?; + // File input and non-typeable form control should have + // been handled in `webdriver_handler.rs`. + if !wait_for_script_response(receiver)?.map_err(|error| WebDriverError::new(error, ""))? { + return Ok(WebDriverResponse::Void); + } let input_events = send_keys(&keys.text); @@ -1655,7 +1666,7 @@ impl Handler { // Step 8.1 self.session_mut()?.input_state_table.borrow_mut().insert( id.clone(), - InputSourceState::Pointer(PointerInputState::new(&PointerType::Mouse)), + InputSourceState::Pointer(PointerInputState::new(PointerType::Mouse)), ); // Step 8.7. Construct a pointer move action. @@ -1702,7 +1713,11 @@ impl Handler { }, }; - let _ = self.dispatch_actions(&[action_sequence]); + let actions_by_tick = self.actions_by_tick_from_sequence(vec![action_sequence]); + + if let Err(e) = self.dispatch_actions(actions_by_tick) { + log::error!("handle_element_click: dispatch_actions failed: {:?}", e); + } // Step 8.17 Remove an input source with input state and input id. self.session_mut()? @@ -1940,7 +1955,9 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler { self.handle_element_css(element, name) }, WebDriverCommand::GetPageSource => self.handle_get_page_source(), - WebDriverCommand::PerformActions(ref x) => self.handle_perform_actions(x), + WebDriverCommand::PerformActions(actions_parameters) => { + self.handle_perform_actions(actions_parameters) + }, WebDriverCommand::ReleaseActions => self.handle_release_actions(), WebDriverCommand::ExecuteScript(ref x) => self.handle_execute_script(x), WebDriverCommand::ExecuteAsyncScript(ref x) => self.handle_execute_async_script(x), diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml index edeaef5408f..034e383c7f0 100644 --- a/ports/servoshell/Cargo.toml +++ b/ports/servoshell/Cargo.toml @@ -90,8 +90,8 @@ hilog = "0.2.0" ipc-channel = { workspace = true, features = ["force-inprocess"] } napi-derive-ohos = "1.0.4" napi-ohos = "1.0.4" -ohos-ime = "0.3.0" -ohos-ime-sys = "0.1.4" +ohos-ime = "0.4.0" +ohos-ime-sys = "0.2.0" ohos-vsync = "0.1.3" xcomponent-sys = { version = "0.3.1", features = ["api-12", "keyboard-types"] } diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 7bbac47cda3..4f3ce2266c5 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -42,13 +42,17 @@ pub struct App { preferences: Preferences, servoshell_preferences: ServoShellPreferences, suspended: Cell<bool>, - windows: HashMap<WindowId, Rc<dyn WindowPortsMethods>>, minibrowser: Option<Minibrowser>, waker: Box<dyn EventLoopWaker>, initial_url: ServoUrl, t_start: Instant, t: Instant, state: AppState, + + // This is the last field of the struct to ensure that windows are dropped *after* all other + // references to the relevant rendering contexts have been destroyed. + // (https://github.com/servo/servo/issues/36711) + windows: HashMap<WindowId, Rc<dyn WindowPortsMethods>>, } /// Action to be taken by the caller of [`App::handle_events`]. diff --git a/ports/servoshell/desktop/egui_glue.rs b/ports/servoshell/desktop/egui_glue.rs index 09ef3735cf8..e27a659dd24 100644 --- a/ports/servoshell/desktop/egui_glue.rs +++ b/ports/servoshell/desktop/egui_glue.rs @@ -39,6 +39,7 @@ pub use egui_winit; pub use egui_winit::EventResponse; use egui_winit::winit; use winit::event_loop::ActiveEventLoop; +use winit::window::Theme; /// Use [`egui`] from a [`glow`] app based on [`winit`]. pub struct EguiGlow { @@ -63,6 +64,7 @@ impl EguiGlow { }) .unwrap(); + let theme = event_loop.system_theme().unwrap_or(Theme::Light); let egui_ctx = egui::Context::default(); Self { egui_winit: egui_winit::State::new( @@ -70,7 +72,7 @@ impl EguiGlow { ViewportId::ROOT, event_loop, None, - event_loop.system_theme(), + Some(theme), None, ), egui_ctx, diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 6095b5c02e7..a1c7576a8c9 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -49,7 +49,6 @@ use crate::desktop::keyutils::CMD_OR_CONTROL; use crate::prefs::ServoShellPreferences; pub struct Window { - winit_window: winit::window::Window, screen_size: Size2D<u32, DeviceIndependentPixel>, inner_size: Cell<PhysicalSize<u32>>, toolbar_height: Cell<Length<f32, DeviceIndependentPixel>>, @@ -72,6 +71,11 @@ pub struct Window { /// The `RenderingContext` of Servo itself. This is used to render Servo results /// temporarily until they can be blitted into the egui scene. rendering_context: Rc<OffscreenRenderingContext>, + + // Keep this as the last field of the struct to ensure that the rendering context is + // dropped first. + // (https://github.com/servo/servo/issues/36711) + winit_window: winit::window::Window, } impl Window { diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index b9587771a50..a1b76758a9a 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -867,14 +867,14 @@ impl HostTrait for HostCallbacks { let mut ime_proxy = self.ime_proxy.borrow_mut(); let ime = ime_proxy.get_or_insert_with(|| { let attach_options = AttachOptions::new(true); - let configbuilder = ohos_ime::TextConfigBuilder::new(); let options = convert_ime_options(input_type, multiline); - let text_config = configbuilder + let text_config = ohos_ime::TextConfigBuilder::new() .input_type(options.input_type) .enterkey_type(options.enterkey_type) .build(); - let editor = RawTextEditorProxy::new(Box::new(ServoIme { text_config })); - ImeProxy::new(editor, attach_options) + let editor = RawTextEditorProxy::new(Box::new(ServoIme { text_config })) + .expect("Failed to create RawTextEditorProxy"); + ImeProxy::new(editor, attach_options).expect("Failed to create IME proxy") }); match ime.show_keyboard() { Ok(()) => debug!("IME show keyboard - success"), diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index e2a5ffc6a1a..e34fa2a2687 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -40,6 +40,7 @@ from servo.platform.build_target import BuildTarget SUPPORTED_ASAN_TARGETS = [ "aarch64-apple-darwin", "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-ohos", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", ] @@ -109,6 +110,8 @@ class MachCommands(CommandBase): opts += ["-v"] if very_verbose: opts += ["-vv"] + if with_asan: + self.config["build"]["with_asan"] = True env = self.build_env() self.ensure_bootstrapped() @@ -136,6 +139,10 @@ class MachCommands(CommandBase): opts += ["-Zbuild-std"] kwargs["target_override"] = target_triple + # With asan we also want frame pointers + if "force-frame-pointers" not in env["RUSTFLAGS"]: + env["RUSTFLAGS"] += " -C force-frame-pointers=yes" + # Note: We want to use the same clang/LLVM version as rustc. rustc_llvm_version = get_rustc_llvm_version() if rustc_llvm_version is None: @@ -144,11 +151,14 @@ class MachCommands(CommandBase): target_clang = f"clang-{llvm_major}" target_cxx = f"clang++-{llvm_major}" if shutil.which(target_clang) is None or shutil.which(target_cxx) is None: - raise RuntimeError(f"--with-asan requires `{target_clang}` and `{target_cxx}` to be in PATH") - env.setdefault("TARGET_CC", target_clang) - env.setdefault("TARGET_CXX", target_cxx) - # TODO: We should also parse the LLVM version from the clang compiler we chose. - # It's unclear if the major version being the same is sufficient. + env.setdefault("TARGET_CC", target_clang) + env.setdefault("TARGET_CXX", target_cxx) + else: + # libasan can be compatible across multiple compiler versions and has a + # runtime check, which would fail if we used incompatible compilers, so + # we can try and fallback to the default clang. + env.setdefault("TARGET_CC", "clang") + env.setdefault("TARGET_CXX", "clang++") # We need to use `TARGET_CFLAGS`, since we don't want to compile host dependencies with ASAN, # since that causes issues when building build-scripts / proc macros. @@ -156,7 +166,6 @@ class MachCommands(CommandBase): env.setdefault("TARGET_CXXFLAGS", "") env["TARGET_CFLAGS"] += " -fsanitize=address" env["TARGET_CXXFLAGS"] += " -fsanitize=address" - env["TARGET_LDFLAGS"] = "-static-libasan" # By default build mozjs from source to enable ASAN with mozjs. env.setdefault("MOZJS_FROM_SOURCE", "1") @@ -190,7 +199,9 @@ class MachCommands(CommandBase): built_binary = self.get_binary_path(build_type, asan=with_asan) if not no_package and self.target.needs_packaging(): - rv = Registrar.dispatch("package", context=self.context, build_type=build_type, flavor=flavor) + rv = Registrar.dispatch( + "package", context=self.context, build_type=build_type, flavor=flavor, with_asan=with_asan + ) if rv: return rv diff --git a/python/servo/command_base.py b/python/servo/command_base.py index abd193eda49..f0f28e5488e 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -305,6 +305,7 @@ class CommandBase(object): self.config["build"].setdefault("incremental", None) self.config["build"].setdefault("webgl-backtrace", False) self.config["build"].setdefault("dom-backtrace", False) + self.config["build"].setdefault("with_asan", False) self.config.setdefault("android", {}) self.config["android"].setdefault("sdk", "") @@ -803,15 +804,16 @@ class CommandBase(object): "--manifest-path", path.join(self.context.topdir, "ports", "servoshell", "Cargo.toml"), ] - if target_override: - args += ["--target", target_override] - elif self.target.is_cross_build(): + + if self.target.is_cross_build(): args += ["--target", self.target.triple()] if type(self.target) in [AndroidTarget, OpenHarmonyTarget]: # Note: in practice `cargo rustc` should just be used unconditionally. assert command != "build", "For Android / OpenHarmony `cargo rustc` must be used instead of cargo build" if command == "rustc": args += ["--lib", "--crate-type=cdylib"] + elif target_override: + args += ["--target", target_override] features = [] diff --git a/python/servo/package_commands.py b/python/servo/package_commands.py index 5e63e6549c0..9bc4d70232d 100644 --- a/python/servo/package_commands.py +++ b/python/servo/package_commands.py @@ -184,6 +184,9 @@ class PackageCommands(CommandBase): "-p", f"buildMode={build_mode}", ] + if with_asan: + hvigor_command.extend(["-p", "ohos-debug-asan=true"]) + # Detect if PATH already has hvigor, or else fallback to npm installation # provided via HVIGOR_PATH if "HVIGOR_PATH" not in env: diff --git a/python/servo/platform/build_target.py b/python/servo/platform/build_target.py index 5f0f500ad58..536b10a8d3d 100644 --- a/python/servo/platform/build_target.py +++ b/python/servo/platform/build_target.py @@ -350,9 +350,8 @@ class OpenHarmonyTarget(CrossBuildTarget): env[f"CXX_{clang_target_triple_underscore}"] = ndk_clangxx # rustc linker env[f"CARGO_TARGET_{rust_target_triple.upper()}_LINKER"] = ndk_clang - # We could also use a cross-compile wrapper - env["RUSTFLAGS"] += f" -Clink-arg=--target={clang_target_triple}" - env["RUSTFLAGS"] += f" -Clink-arg=--sysroot={ohos_sysroot_posix}" + + link_args = ["-fuse-ld=lld", f"--target={clang_target_triple}", f"--sysroot={ohos_sysroot_posix}"] env["HOST_CFLAGS"] = "" env["HOST_CXXFLAGS"] = "" @@ -398,6 +397,49 @@ class OpenHarmonyTarget(CrossBuildTarget): bindgen_extra_clangs_args = bindgen_extra_clangs_args + " " + ohos_cflags_str env[bindgen_extra_clangs_args_var] = bindgen_extra_clangs_args + # On OpenHarmony we add some additional flags when asan is enabled + if config["build"]["with_asan"]: + # Lookup `<sdk>/native/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos/libclang_rt.asan.so` + lib_clang = llvm_toolchain.joinpath("lib", "clang") + children = [f.path for f in os.scandir(lib_clang) if f.is_dir()] + if len(children) != 1: + raise RuntimeError(f"Expected exactly 1 libclang version: `{children}`") + lib_clang_version_dir = pathlib.Path(children[0]) + libclang_arch = lib_clang_version_dir.joinpath("lib", clang_target_triple).resolve() + libasan_so_path = libclang_arch.joinpath("libclang_rt.asan.so") + libasan_preinit_path = libclang_arch.joinpath("libclang_rt.asan-preinit.a") + if not libasan_so_path.exists(): + raise RuntimeError(f"Couldn't find ASAN runtime library at {libasan_so_path}") + link_args.extend( + [ + "-fsanitize=address", + "--rtlib=compiler-rt", + "-shared-libasan", + str(libasan_so_path), + "-Wl,--whole-archive", + "-Wl," + str(libasan_preinit_path), + "-Wl,--no-whole-archive", + ] + ) + + # Use the clangrt from the NDK to use the same library for both C++ and Rust. + env["RUSTFLAGS"] += " -Zexternal-clangrt" + + asan_compile_flags = ( + " -fsanitize=address -shared-libasan -fno-omit-frame-pointer -fsanitize-recover=address" + ) + + arch_asan_ignore_list = lib_clang_version_dir.joinpath("share", "asan_ignorelist.txt") + if arch_asan_ignore_list.exists(): + asan_compile_flags += " -fsanitize-system-ignorelist=" + str(arch_asan_ignore_list) + else: + print(f"Warning: Couldn't find system ASAN ignorelist at `{arch_asan_ignore_list}`") + env["TARGET_CFLAGS"] += asan_compile_flags + env["TARGET_CXXFLAGS"] += asan_compile_flags + + link_args = [f"-Clink-arg={arg}" for arg in link_args] + env["RUSTFLAGS"] += " " + " ".join(link_args) + def binary_name(self) -> str: return "libservoshell.so" diff --git a/support/hitrace-bencher/runs.json b/support/hitrace-bencher/runs.json index 2513e3f57d1..63c64f41a66 100644 --- a/support/hitrace-bencher/runs.json +++ b/support/hitrace-bencher/runs.json @@ -25,6 +25,28 @@ "start_fn_partial": "on_surface_created_cb", "end_fn_partial": "PageLoadEndedPrompt" } + ], + "point_filters": [ + { + "name": "Explicit", + "match_str": "explicit" + }, + { + "name": "Resident", + "match_str": "resident" + }, + { + "name": "LayoutThread", + "match_str": "layout-thread" + }, + { + "name": "image-cache", + "match_str": "image-cache" + }, + { + "name": "JS", + "match_str": "js" + } ] }, { @@ -39,7 +61,28 @@ "start_fn_partial": "on_surface_created_cb", "end_fn_partial": "PageLoadEndedPrompt" } + ], + "point_filters": [ + { + "name": "Explicit", + "match_str": "explicit" + }, + { + "name": "Resident", + "match_str": "resident" + }, + { + "name": "LayoutThread", + "match_str": "layout-thread" + }, + { + "name": "image-cache", + "match_str": "image-cache" + }, + { + "name": "JS", + "match_str": "js" + } ] } ] - diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index 3a7faebb345..7efcfa22eb2 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -761,6 +761,13 @@ {} ] ], + "chrome-420329041-crash.html": [ + "2b236a371e524da0ac5669ad7fc5f45259c089c5", + [ + null, + {} + ] + ], "grid-anchor-center-crash.html": [ "bab4eed6b66dfb846ef451f14ced6eb2a0867cc1", [ @@ -2841,6 +2848,17 @@ ] ] }, + "css-gaps": { + "grid": { + "grid-gap-decorations-041-crash.html": [ + "be3e2280b5f52dcc60a4fe418ae67af3ec23da6b", + [ + null, + {} + ] + ] + } + }, "css-grid": { "abspos": { "abspos-in-flexbox-in-grid-crash.html": [ @@ -3899,6 +3917,13 @@ {} ] ], + "repeated-table-column.html": [ + "0d6a1accfd122c38180f8d20904a7e16a131dd41", + [ + null, + {} + ] + ], "repeated-table-footer-in-caption-nested-multicol.html": [ "d630abe8bbb1e752d3a7c559e4c49864233c44f9", [ @@ -5953,6 +5978,13 @@ ], "scoped": { "crashtests": { + "participating-scope.html": [ + "26979e58458d0a27679f6aa079f38f71eddc03df", + [ + null, + {} + ] + ], "shadow-dom.html": [ "a2faafc1694e15f5c513655e57e320325bd4f45a", [ @@ -6975,13 +7007,6 @@ {} ] ], - "indent-outdent-after-closing-editable-dialog-element.html": [ - "7f73de048d714c99ce47ae4da61d7128e53216e8", - [ - null, - {} - ] - ], "insert-image-with-joining-header-element-and-body.html": [ "cf5b2df225be06c833fea6d3bf2ceab6b1231018", [ @@ -8178,6 +8203,13 @@ {} ] ], + "select-highlight-crash.html": [ + "a45120a245984408b65b1e99f1cfba265dad78fc", + [ + null, + {} + ] + ], "select-listitems-crash.html": [ "cdda243877f1e3c699410dd67e25548880b868b9", [ @@ -8462,6 +8494,13 @@ {} ] ], + "popover-root-crash.html": [ + "86498607730f883920419ac4815dce128196d9f5", + [ + null, + {} + ] + ], "popover-undefined-remove-crash.html": [ "3c273ea6f344d179a3d010d20f0779b3721abb40", [ @@ -23715,6 +23754,13 @@ null, {} ] + ], + "ua-shadow-contents-manual.html": [ + "23908ca927426be40895156d26b94fdbc40b090d", + [ + null, + {} + ] ] }, "images": { @@ -136900,6 +136946,35 @@ } ] ], + "corner-shape-img.html": [ + "82662d255623d387080bcc8be2e33570f0ed4c62", + [ + null, + [ + [ + "/css/css-borders/tentative/corner-shape/corner-shape-img-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 64 + ], + [ + 0, + 100 + ] + ] + ] + ] + } + ] + ], "corner-shape-inset-shadow.html": [ "7a83caff70c08b74d5d6c2540684c49f8e893f72", [ @@ -136988,7 +137063,7 @@ ] ], "corner-shape-render-fuzzy.html": [ - "12cd2546bf484282a8cab7163c610b5b88d0b9f8", + "2d4b56f831b91eb70fd44abc02000213664a480b", [ "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?border-radius=30%&corner-shape=superellipse(-1.5)&box-shadow=10px%2010px%200%2010px%20black", [ @@ -137250,10 +137325,10 @@ } ], [ - "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px&border-left-color=purple", + "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px", [ [ - "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px&border-left-color=purple", + "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px", "==" ] ], @@ -137485,7 +137560,7 @@ ] ], "corner-shape-render-precise.html": [ - "5293589222a3f2d918bdbfeecd11280f667578c2", + "4a0c575b3b7cef4cbfb1dea4efc53ec40e01ef13", [ "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?border-radius=50%&corner-shape=bevel&box-shadow=10px%2010px%200%2010px%20black", [ @@ -137669,6 +137744,32 @@ } ], [ + "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-shape=notch&border-radius=30px&border-width=30px", + [ + [ + "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=notch&border-radius=30px&border-width=30px", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 180 + ], + [ + 0, + 350 + ] + ] + ] + ] + } + ], + [ "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-shape=square&border-bottom-left-radius=5px", [ [ @@ -137877,10 +137978,10 @@ } ], [ - "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-left-shape=bevel&border-width=10px&border-color=black", + "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-left-shape=bevel&border-width=10px", [ [ - "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-left-shape=bevel&border-width=10px&border-color=black", + "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-left-shape=bevel&border-width=10px", "==" ] ], @@ -138007,10 +138108,10 @@ } ], [ - "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-right-shape=bevel&border-width=10px&border-color=black", + "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-right-shape=bevel&border-width=10px", [ [ - "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-right-shape=bevel&border-width=10px&border-color=black", + "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-right-shape=bevel&border-width=10px", "==" ] ], @@ -176879,19 +176980,6 @@ {} ] ], - "flexbox_columns.html": [ - "d39c2db55f2a144e5ab9efa713572bd27da72c07", - [ - null, - [ - [ - "/css/css-flexbox/flexbox_columns-ref.html", - "==" - ] - ], - {} - ] - ], "flexbox_direction-column-reverse.html": [ "8d2cd330e4c65c46a4ff2c8e36811c88c7bdc4e6", [ @@ -186558,6 +186646,21 @@ ] ] }, + "css-forms": { + "datetime-stacking-context.html": [ + "4754cacf09d6cc1c9aaccbb760e32ca8991e6502", + [ + null, + [ + [ + "/css/css-forms/datetime-stacking-context-ref.html", + "==" + ] + ], + {} + ] + ] + }, "css-gaps": { "agnostic": { "gap-decorations-003.html": [ @@ -187383,6 +187486,32 @@ {} ] ], + "grid-gap-decorations-040.html": [ + "4bab26db550308a111608e3b0af6d15735c6d041", + [ + null, + [ + [ + "/css/css-gaps/grid/grid-gap-decorations-040-ref.html", + "==" + ] + ], + {} + ] + ], + "grid-gap-decorations-042.html": [ + "5b2b4936980641296cf1c97f80b4bdbecd19ce2f", + [ + null, + [ + [ + "/css/css-gaps/grid/grid-gap-decorations-042-ref.html", + "==" + ] + ], + {} + ] + ], "grid-gap-decorations-38.html": [ "8b87bcd4860ac50a1c2f3de98cec9599bebb77a3", [ @@ -192381,6 +192510,19 @@ {} ] ], + "grid-item-inline-contribution-004.html": [ + "a4e3cd6f3a47d18efc2a27d1f1e410d5ef92cff5", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "grid-item-margins-and-writing-modes-001.html": [ "5209940a9699d6a108f815f81eb4d3b4527dcf79", [ @@ -211752,6 +211894,37 @@ ] }, "css-masking": { + "animations": { + "clip-path-interpolation-shape-arc-direction-agnostic-radius.html": [ + "aa91e1828a7841c4036f6c2d15639ebd2f1bf4e4", + [ + null, + [ + [ + "/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 10 + ], + [ + 0, + 360 + ] + ] + ] + ] + } + ] + ] + }, "clip": { "clip-absolute-positioned-001.html": [ "c5b0d9001c442012aea33142d47ca1a8d68e319e", @@ -215146,6 +215319,35 @@ {} ] ], + "clip-path-shape-011.html": [ + "fc1927591e086bf341fcd9fa87a86429e1862053", + [ + null, + [ + [ + "/css/css-masking/clip-path/reference/clip-path-shape-arc-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 64 + ], + [ + 0, + 128 + ] + ] + ] + ] + } + ] + ], "clip-path-shape-foreignobject-non-zero-xy.html": [ "4e221f36e4cb7bc698f1929dcc09096114ab2693", [ @@ -250746,6 +250948,19 @@ {} ] ], + "image-max-width-and-height-behaves-as-auto.html": [ + "dcb00ba6a5cdcc1c310e26792172da0490b927c4", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "image-min-max-content-intrinsic-size-change-001.html": [ "b7c57bb7abe161bf66cdec988953ba1d2c0035ab", [ @@ -251815,6 +252030,84 @@ {} ] ], + "responsive-iframe-cross-origin-no-match-element.sub.tentative.html": [ + "08dda4e6b7660bdea83681b52fa15ae93ad32ceb", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-unsized-ref.html", + "==" + ] + ], + {} + ] + ], + "responsive-iframe-cross-origin-not-embedded-sized.sub.tentative.html": [ + "d9b33973a04c7eb3f8a4756f4d15fda0970bae0d", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-unsized-ref.html", + "==" + ] + ], + {} + ] + ], + "responsive-iframe-cross-origin.sub.tentative.html": [ + "22f6f1d1581af4bc515877dee2f8d119274817e3", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-ref.html", + "==" + ] + ], + {} + ] + ], + "responsive-iframe-no-match-element.html": [ + "685eb60f123fb54066cca118ab5cb29cfcd89db9", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-unsized-ref.html", + "==" + ] + ], + {} + ] + ], + "responsive-iframe-not-embedded-sized.tentative.html": [ + "0d1f91c5789afd8e9af69c2f19204dc0cae60bf3", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-unsized-ref.html", + "==" + ] + ], + {} + ] + ], + "responsive-iframe.tentative.html": [ + "229cf01844968e7aa55c165b128435ea455a40d6", + [ + null, + [ + [ + "/css/css-sizing/responsive-iframe-ref.html", + "==" + ] + ], + {} + ] + ], "slice-intrinsic-size.html": [ "05ce6e46304adda6aab773147e8a32d2564680b6", [ @@ -263486,6 +263779,19 @@ {} ] ], + "text-autospace-edit-001.html": [ + "80c46f54d20ff9249a49d73e55b331a8368df4e1", + [ + null, + [ + [ + "/css/css-text/text-autospace/text-autospace-edit-001-ref.html", + "==" + ] + ], + {} + ] + ], "text-autospace-first-line-001.html": [ "0e0f848b062747e6cb36ec4899d2bbfff10fcb44", [ @@ -263580,6 +263886,19 @@ ], {} ] + ], + "text-autospace-vs-001.html": [ + "31c7bbf6073ffac1f614846c6c033cca7ff7d4b4", + [ + null, + [ + [ + "/css/css-text/text-autospace/text-autospace-vs-001-ref.html", + "==" + ] + ], + {} + ] ] }, "text-encoding": { @@ -272836,6 +273155,19 @@ {} ] ], + "word-break-keep-all-u002d.html": [ + "df3ebb3f22111f4935d3787674a18c7a833083c1", + [ + null, + [ + [ + "/css/css-text/word-break/reference/word-break-keep-all-u002d-ref.html", + "==" + ] + ], + {} + ] + ], "word-break-manual-001.html": [ "09d803b0fc1f75f2f253687c5c9dc3305d77616f", [ @@ -306974,7 +307306,7 @@ ] ], "auto-name-from-id.html": [ - "d3430c93a1d2043146e7205c2734a2b8b19af2e0", + "20080d7623a9ce4880d7a065cf729f0f2b3470e1", [ null, [ @@ -307975,6 +308307,35 @@ } ] ], + "inline-child-with-composited-filter.html": [ + "36ba9803e1edb2c87d8d3e57b5f2589d349df964", + [ + null, + [ + [ + "/css/css-view-transitions/inline-child-with-filter-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 2 + ], + [ + 0, + 2400 + ] + ] + ] + ] + } + ] + ], "inline-child-with-filter.html": [ "61f0f1f6a8c389cd7298c56d8c2e35c3f101027b", [ @@ -308031,7 +308392,7 @@ ] ], "inline-with-offset-from-containing-block.html": [ - "31f8449ff630fe6844eb16b46e445ec840d550d8", + "77fb0570966e47909b7b9d06f1330adcd5233ac8", [ null, [ @@ -308051,7 +308412,7 @@ ], [ 0, - 1500 + 1633 ] ] ] @@ -309600,7 +309961,7 @@ ] ], "nested-exit.tentative.html": [ - "83570762061638bd2a780922e45cf39da100d713", + "847058be2b4a1659fb4d512e0906b55fa96c4a38", [ null, [ @@ -309774,7 +310135,7 @@ ] ], "rounded-border-clipper.html": [ - "239bcdd791db41383dd66765269590d84627a0a3", + "098e5566585930a89378c5a8a6ede536fea9e124", [ null, [ @@ -309902,7 +310263,7 @@ ] ], "new-content-captures-different-size.html": [ - "eeb7347981daac829fd17d85ada19730fe22af32", + "0a754c651ffa2f0e7cbd957ab4ad2b8bb35f2cd2", [ null, [ @@ -309922,7 +310283,7 @@ ], [ 0, - 15000 + 15393 ] ] ] @@ -311275,7 +311636,7 @@ ] ], "pseudo-with-classes-view-transition-group.html": [ - "f9fe20222589283591cee10fa33f88d8d47f15ad", + "14717728b15ec9023a1fdeb0dc41c639588d7fee", [ null, [ @@ -311438,7 +311799,7 @@ ], "scoped": { "nested-scope.html": [ - "9fff44e5e732edd1946adf414a8f23668022edda", + "b9cc25c3338912ae91da453c20924dd5cc90e294", [ null, [ @@ -312471,6 +312832,19 @@ {} ] ], + "height.html": [ + "f608765bcf1f60857bba1ab8a4db820e68577941", + [ + null, + [ + [ + "/css/css-viewport/zoom/green-square-100px.html", + "==" + ] + ], + {} + ] + ], "iframe-zoom-nested.html": [ "9dc99a0fa55ea28e4a7e36ecd90166aef64771fb", [ @@ -312511,7 +312885,7 @@ ] ], "inherited-length.html": [ - "d83111a43528b7f0cf08732084330a43148d998b", + "571b533d5d6fd81ba8a334fa23ed21a120daecc5", [ null, [ @@ -312575,6 +312949,58 @@ {} ] ], + "max-height.html": [ + "6a0dcd826e245f82e76ee2bff177ff0270299701", + [ + null, + [ + [ + "/css/css-viewport/zoom/green-square-100px.html", + "==" + ] + ], + {} + ] + ], + "max-width.html": [ + "b6d4139e30a9754eac02ad85c4348adacf793158", + [ + null, + [ + [ + "/css/css-viewport/zoom/green-square-100px.html", + "==" + ] + ], + {} + ] + ], + "min-height.html": [ + "31a47d92b213baf1fe8ae3d88607b41e29a4c577", + [ + null, + [ + [ + "/css/css-viewport/zoom/green-square-100px.html", + "==" + ] + ], + {} + ] + ], + "min-width.html": [ + "bd1cda23d3a3b0d0197c63ea536b2b5c85d2b66f", + [ + null, + [ + [ + "/css/css-viewport/zoom/green-square-100px.html", + "==" + ] + ], + {} + ] + ], "relative-units-from-parent.html": [ "57df82b6f1c5b8cd9ef405cdc1097826de0e061f", [ @@ -323706,6 +324132,19 @@ {} ] ], + "orthogonal-cell-001.html": [ + "12e996ac902b138e53936f39f7c2237978f9a1ae", + [ + null, + [ + [ + "/css/css-writing-modes/orthogonal-cell-001-ref.html", + "==" + ] + ], + {} + ] + ], "orthogonal-child-with-border.html": [ "877cce5a710f5f5e613c02f581c216070fdd0f41", [ @@ -339456,6 +339895,19 @@ {} ] ], + "visited-nested.html": [ + "57220446c8688a3a12fcb36aeb00b904c901fd3d", + [ + null, + [ + [ + "/css/selectors/visited-nested-ref.html", + "==" + ] + ], + {} + ] + ], "xml-class-selector.xml": [ "5666c0065d6262e0ca3c586d145a67e7f9c2a3cf", [ @@ -339469,20 +339921,7 @@ {} ] ] - }, - "visited-nested.html": [ - "57220446c8688a3a12fcb36aeb00b904c901fd3d", - [ - null, - [ - [ - "/css/visited-nested-ref.html", - "==" - ] - ], - {} - ] - ] + } }, "custom-elements": { "form-associated": { @@ -351498,6 +351937,32 @@ {} ] ], + "size-with-color-or-noshade.html": [ + "db1d583934e6df482cde846eda757e010e7d0310", + [ + null, + [ + [ + "/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade-ref.html", + "==" + ] + ], + {} + ] + ], + "size.html": [ + "2162131b853ed77917ab373f4fb2c70c536e453c", + [ + null, + [ + [ + "/html/rendering/non-replaced-elements/the-hr-element-0/size-ref.html", + "==" + ] + ], + {} + ] + ], "width.html": [ "a436d2ae25a6b03f320bda066f32c374b84e0d92", [ @@ -356825,6 +357290,34 @@ {} ] ], + "permission-icon": { + "icon-hidden-reftest.html": [ + "79055da1badfc827e5cc02ed3be7db3842b49855", + [ + null, + [ + [ + "/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html", + "!=" + ] + ], + {} + ] + ], + "icon-unique-per-type-reftest.html": [ + "d51b1c4d398a42c8e59f047c0e457c533eae16ee", + [ + null, + [ + [ + "/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html", + "!=" + ] + ], + {} + ] + ] + }, "pseudo-elements-in-div.tentative.html": [ "24a2be07fabae34fd969fa89c233b2a209c0c08f", [ @@ -364728,6 +365221,19 @@ {} ] ], + "image-modify-href-4.svg": [ + "f7e550e5defb0b1eba85edad430b0cef760223e6", + [ + null, + [ + [ + "/svg/embedded/reference/green-rect-100x100.svg", + "==" + ] + ], + {} + ] + ], "image-remove-href-1.svg": [ "f35fa08f561dc38363d5c83918ec789fbc523b60", [ @@ -376553,6 +377059,10 @@ [] ], "permissions-policy": { + "WEB_FEATURES.yml": [ + "da7599308cc01a95696e952d02553df47ba3f6bf", + [] + ], "ch-ua-high-entropy-values-disabled-by-permissions-policy.https.sub.html.headers": [ "fcf474880843e220faff943f8946f83b514208a4", [] @@ -395794,7 +396304,7 @@ ], "resources": { "container-timing-helpers.js": [ - "a80ad964fef311f55062631d5548a6d8f0eecb3f", + "8b3f21dff56f9cef78b8a7c4df785a5b366034e5", [] ], "square100.png": [ @@ -397312,7 +397822,7 @@ [] ], "script-src-strict_dynamic_parser_inserted.html.headers": [ - "b7918c93323eff9db66ad26a73b78798d35e5f7b", + "9d0b3b93d44db43be7d19c34483bc1e63ef777a0", [] ], "script-src-strict_dynamic_parser_inserted_correct_nonce.html.headers": [ @@ -397723,7 +398233,7 @@ }, "cookie-store": { "META.yml": [ - "68c30024552f526e2d34f42eb22416ac3b585114", + "4bbc6311bdceece7580ba9c38344081e0b4aba57", [] ], "README.md": [ @@ -397736,7 +398246,7 @@ [] ], "cookie-test-helpers.js": [ - "8e23ff2c4225da41788542908fae6593860146ce", + "82ca135f88e423440c3c3fd2bb02df4ed39aa436", [] ], "cookie_helper.py": [ @@ -418479,6 +418989,10 @@ "1eb6cbd8df349f0a27b1575b8a77583c95b44a42", [] ], + "corner-shape-img-ref.html": [ + "565698f79ec3fe89a9078a2c6277b38f494dfd99", + [] + ], "corner-shape-inset-shadow-ref.html": [ "fa36c9d6ecc527fee37bb589c3c5194df1ff2291", [] @@ -418497,11 +419011,11 @@ ], "resources": { "corner-shape.js": [ - "4757a43ad051f42a88ddefeba344bcea0b9a0149", + "c08a95c7d7511e84eb92015d13578e23ad2f2ec5", [] ], "corner-utils.js": [ - "ad3b235addff11e418d78e372b20c09a2ebd4a19", + "b6f329e82484f14f853c999dbd99a15771db1e8d", [] ], "resolve-corner-style.js": [ @@ -423743,10 +424257,6 @@ "3c8e1f475a337e111b7290465b67ede2b35ac4bb", [] ], - "flexbox_columns-ref.html": [ - "b8c7a22569882c3687441af49ed683dcc37634bd", - [] - ], "flexbox_direction-column-ref.html": [ "9b91d50345528741a8cf3d889bc8212282e678cb", [] @@ -432682,6 +433192,12 @@ ] } }, + "css-forms": { + "datetime-stacking-context-ref.html": [ + "95bee383d2117d1c054e4706abfd130149d31fc8", + [] + ] + }, "css-gaps": { "agnostic": { "gap-decorations-001-ref.html": [ @@ -432911,6 +433427,14 @@ "grid-gap-decorations-037-ref.html": [ "4a2ee5bd5c6fbdb25e5a70eac56a9b0bbac5d56f", [] + ], + "grid-gap-decorations-040-ref.html": [ + "2988cf534a969828f1e0b9756a8bf52747966ee8", + [] + ], + "grid-gap-decorations-042-ref.html": [ + "ed44f7a2de37d31d57391731b2b8d7f7886790ad", + [] ] }, "multicol": { @@ -437413,6 +437937,10 @@ "WEB_FEATURES.yml": [ "758ef35275eeacc96b6e584f672f86c4b170e0e1", [] + ], + "clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html": [ + "2869d38a982b23d72ae49543d16d01bda6f28b21", + [] ] }, "clip": { @@ -437823,6 +438351,10 @@ "b74e6abdd9e7c02adf5392f02854ee61f05bc38f", [] ], + "clip-path-shape-arc-ref.html": [ + "9cbe55de210580ce38096bf106493d10f33dc7cd", + [] + ], "clip-path-shape-control-points-ref.html": [ "ebcc87bcf6482b22974787ae80df052b0c67ee02", [] @@ -438436,7 +438968,7 @@ [] ], "column-height-009-ref.html": [ - "034440ebd5c81be43f0d871d3adb276b2a735768", + "4696d79695bdd6a5901e4d0d00fffc4935438163", [] ], "column-pseudo-background-color-ref.html": [ @@ -441818,6 +442350,10 @@ ] }, "overlay": { + "WEB_FEATURES.yml": [ + "a1a4402ee421efa24e9b02a2337c90812759a4e2", + [] + ], "green-ref.html": [ "bef7405e96f8181f88fb073ebd212b4af6382e33", [] @@ -445127,6 +445663,24 @@ "11afa34a654ec071c00971b11a2261ff95397904", [] ], + "resources": { + "iframe-contents-unsized.html": [ + "db1931a27d5a7ff84d30edf370688d0c33b139b9", + [] + ], + "iframe-contents.html": [ + "3b7406e1e4064bc0f9f829907bfe462c8b6d3891", + [] + ] + }, + "responsive-iframe-ref.html": [ + "c446474f71a9e0f443ef7f57226a16a1d25f8444", + [] + ], + "responsive-iframe-unsized-ref.html": [ + "2fa633e086dceeb9e05063eb92783295351b4d44", + [] + ], "slice-intrinsic-size-ref.html": [ "ca4887af7a862b6629a579b306638263ca5192b3", [] @@ -448188,6 +448742,10 @@ "d26fae09b03fc19fc561abcc4ab4487b3be91b3f", [] ], + "text-autospace-edit-001-ref.html": [ + "ca95e197462730462dbd403871173d6b9873c3b0", + [] + ], "text-autospace-first-line-001-ref.html": [ "4adf09f200df40141453a89171fa1392740cfbd3", [] @@ -448219,6 +448777,10 @@ "text-autospace-vertical-upright-001-ref.html": [ "1c9caec112a3f9e132a8b612f748a23556a56de2", [] + ], + "text-autospace-vs-001-ref.html": [ + "b02b4f7a20deeffd4f72b8ed8aa5103e3e2e6518", + [] ] }, "text-encoding": { @@ -449599,6 +450161,10 @@ "cbfd3476089a962634e21ead1122f105f3f58c92", [] ], + "word-break-keep-all-u002d-ref.html": [ + "4a6553cfe838e41c67f0ccaa9d7e04b6904a1e62", + [] + ], "word-break-manual-001-ref.html": [ "f51208ab95fd4aaa804684673f09acf1492ded4d", [] @@ -454721,6 +455287,10 @@ "bf99b25f76b176520715a245ef3abf01258fdc5a", [] ], + "inline-child-with-composited-filter-ref.html": [ + "9dd26f2c3b1afb49d60bedb5e721dcb1f193d423", + [] + ], "inline-child-with-filter-ref.html": [ "44a41f1bf93366e06f2eae0cbfcd4acb126d192f", [] @@ -454884,7 +455454,7 @@ [] ], "auto-name-from-id.html": [ - "71ea52a273e3fca98440cdefc50c77c722663a21", + "dc2cf8fd29b2cf46e1c4c57aa2c34f6272a51b20", [] ], "chromium-paint-holding-timeout.html": [ @@ -454998,7 +455568,7 @@ ], "resources": { "compute-common.css": [ - "20337ccce5f3387e7e70e6fb219544369b74aa06", + "d8f46179b40fd8d55b2bdc125a04cf26aadf0fba", [] ], "compute-test.js": [ @@ -455279,7 +455849,7 @@ [] ], "nested-scope-ref.html": [ - "804741cd6db993392ba8785e8c87f9c16894af41", + "951c0928687dcd6edb32e8e3aa7307bf3d6b3923", [] ] }, @@ -456091,6 +456661,10 @@ "28f0e333282a714715f8e593ac810ff3704d029e", [] ], + "orthogonal-cell-001-ref.html": [ + "f50121ef16d240e2991a9626b1dfe4e72a893fb3", + [] + ], "orthogonal-containing-block-height-changes-ref.html": [ "b7d32e4dc27ba972345f6dc9be81b4079ed54574", [] @@ -460673,6 +461247,10 @@ "64300b13f4291f416eac17f70ff62e2febf604fe", [] ], + "visited-nested-ref.html": [ + "22f4ecf0d7bbcef307fd679ae0905f9b5318f690", + [] + ], "xml-class-selector-ref.xml": [ "6b44280737ab254649036ff50808b764bc87cc67", [] @@ -460923,11 +461501,7 @@ "e7775276038f307b7cdb0a75d19ee24f67619c2a", [] ] - }, - "visited-nested-ref.html": [ - "22f4ecf0d7bbcef307fd679ae0905f9b5318f690", - [] - ] + } }, "custom-elements": { "META.yml": [ @@ -466607,7 +467181,7 @@ ], "resources": { "fetch-private-http.html": [ - "e372d90b26a02bdfa0b9a34c9c8ad956b5d0cc02", + "517629b758e89d4e07f2278d0ae7cb1a45b19c17", [] ], "fetch-private.html": [ @@ -466615,7 +467189,7 @@ [] ], "fetch-public-http-wrong-address-space.html": [ - "1d149d00cb351b9aaa4402b9b8b7d975d56a9acb", + "c15a87ff7b9206576710b5763a64ac6a9a704d71", [] ], "support.sub.js": [ @@ -479883,6 +480457,14 @@ "5cd35c83ada3470ad7a16d14a5028b01596bb60c", [] ], + "size-ref.html": [ + "03a21eb45737ef46247d8bdd61fe5ea0dcefef3e", + [] + ], + "size-with-color-or-noshade-ref.html": [ + "d6300e250d97d113e9ef358daa300de4bd593850", + [] + ], "width-ref.html": [ "71e7651c1ab6927f1be436ef8ff749f920924562", [] @@ -482744,6 +483326,12 @@ "8b48bb93febed1c7fd88f62fe747b3379b349e22", [] ], + "permission-icon": { + "standard-location-permission-element-ref.html": [ + "15ffe751c51b3f8caeaa8b93f1286a3950c9a815", + [] + ] + }, "pseudo-elements-in-div-ref.html": [ "8e6267f9aa350333cef620d248dfce40b85b43e2", [] @@ -486210,7 +486798,7 @@ "system-state-and-capabilities": { "the-navigator-object": { "WEB_FEATURES.yml": [ - "a1af3e21a48f5941a078209963d1ae7bc379dd59", + "7a364e140958e3cea3be9fd13654afc504006664", [] ], "resources": { @@ -488484,6 +489072,10 @@ "6f93db15a74e052913a277e5130226280a3f9311", [] ], + "scoped-custom-elements-registry.idl": [ + "46ca2d6b9c45805d8aa684af7fe91af6dd5d7919", + [] + ], "screen-capture.idl": [ "db9282ce0a57bb3b84ea45f5ed2d7e69bc3a8a32", [] @@ -489198,6 +489790,10 @@ "10c6aa36cecf918928298102d1934c2ff79d01f2", [] ], + "WEB_FEATURES.yml": [ + "335b072c1868c1817dbe7ed6c1901907aa8decbc", + [] + ], "resources": { "slow-image.py": [ "d9f09b8bca78dd1e054fdfcb108fe9066a31db3b", @@ -489214,7 +489810,7 @@ } }, "lint.ignore": [ - "10b5dadba749857f16dc92f348fff31b4400dca3", + "60b0f65a6f43a560c5d86ffe937359d5c9717597", [] ], "loading": { @@ -492288,7 +492884,7 @@ [] ], "nel.sub.js": [ - "26ddd897c2fb72b3e48fe572bcfba745729ddfe1", + "f9dfec1dad8c774e2dc04ff7787edaab3554cc96", [] ], "no-policy-pass.png": [ @@ -497060,6 +497656,10 @@ "edb4759954d4c3829ddc0aa2ecac84ef7d241e37", [] ], + "testdriver-actions.js.headers": [ + "5e8f640c6659d176eaca4c71cc1798b7285540b7", + [] + ], "testdriver-vendor.js": [ "3e88403636396c439759705c751433b28e05f3ab", [] @@ -501328,13 +501928,23 @@ [] ], "soft-navigation-helper.js": [ - "48e7b58d8d1a6a0f05a5c4e30efc3faca83eedaf", + "5860738225b8ed03a2063b1c2b9eef7884f33ee5", [] ], "soft-navigation-test-helper.js": [ "a572f55e66dbce825d399f61c4a2dfa34df9b4ca", [] ] + }, + "smoke": { + "tentative": { + "resources": { + "other_window.html": [ + "406d39c3691853a03731287b2a02f215dcbf721c", + [] + ] + } + } } }, "speculation-rules": { @@ -501383,13 +501993,17 @@ [] ], "executor.sub.html": [ - "bb2d58dc9c9cfac6d98380b0b587bc242fbd5e11", + "b89c45e4f5c25b274925afd6569d6384d5183fe4", [] ], "executor.sub.html.headers": [ "4030ea1d3ddb186a2b5361eb1a3f2404a45531fc", [] ], + "post-navigation-handler.py": [ + "1749517710ed19eda399f01321e1ffcedfc9b09b", + [] + ], "prefetch.py": [ "14ac4d1699ea0c52ac4b40f0a4a0f71c99147073", [] @@ -501610,6 +502224,10 @@ "10a48df58cf9dd9f13eca87e69c54098af1b64b0", [] ], + "image-with-headers-stash.py": [ + "dcb8838d4a167d91ded325e7d3fc6b50055c7746", + [] + ], "indexedb-utils.js": [ "7c57000d5cf48a3bbf74c0b0d8f812922f0575ef", [] @@ -513897,7 +514515,7 @@ [] ], "base.py": [ - "7cea14c7a44b04b1174949816a29bd7d30ef8b16", + "707b539ec769696948b6ee9e4c35991b1f1afad8", [] ], "bufferhandler.py": [ @@ -515242,11 +515860,11 @@ [] ], "firefox_android.py": [ - "7bb2e57d417941bbb1710d6c11b8412f45d6fa7d", + "d0cd7411af0e29a14a3d2e7dfb955988f8a875f1", [] ], "headless_shell.py": [ - "b6f7a40f8a92c347add74a5f69f9996107df46cc", + "ccd5620365a03a2a6543087f6046086f1cc7a52c", [] ], "ladybird.py": [ @@ -515272,11 +515890,11 @@ ] }, "servo.py": [ - "266aec8fced6eb4cc5ca12a15cb8d938220e65ed", + "49a2613ff12ba4f3b085549a31266a21861bbaf1", [] ], "servodriver.py": [ - "5011a8fd8592d32af1a8313dd4ba6535a9cc384a", + "a8aa5ae001b1ecd53a7f2f4515efa299c9ce8809", [] ], "webkit.py": [ @@ -515322,7 +515940,7 @@ [] ], "executorchrome.py": [ - "1e588d5bfbfd26334fbcf980e0fe8f0bea804f87", + "3284e6c8091b7c17ebe6fe158ba4ff09afb628da", [] ], "executoredge.py": [ @@ -515497,7 +516115,7 @@ [] ], "testrunner.py": [ - "19c814bb6c94fb11ddd2b132cf5d156e58956c7b", + "be310944fd878b4bcf74e6f052e2a8cc99d3e157", [] ], "tests": { @@ -516192,7 +516810,7 @@ ], "resources": { "block-text-node-insertion.js": [ - "e9797756417e1c2a42158edab6bb25b37e7d518a", + "dd85483a44fa4df26a2f890f06416b6ab5babca8", [] ] }, @@ -516571,6 +517189,10 @@ "META.yml": [ "c994748e0f27bcc75019ad7a20816ee138d15f91", [] + ], + "WEB_FEATURES.yml": [ + "2d331cf4060d293c912f564e28b8fff089cfeb09", + [] ] }, "uievents": { @@ -517255,6 +517877,10 @@ "b92b53ee45cd98933a3c2fbcf404478eb8f66a06", [] ], + "urlpattern-generate-test-data.json": [ + "c118f0a73b5fe108ab1a1f39d41148648daa7baa", + [] + ], "urlpattern-hasregexpgroups-tests.js": [ "4be886e4a5390d7d43356d853cc00c7bbb23d361", [] @@ -524436,6 +525062,10 @@ "58ee7cca1ab3e9856e380eaccde042d5700c2603", [] ], + "WEB_FEATURES.yml": [ + "1687ef742e2b51872debc6da074022449c2215df", + [] + ], "Worker-creation-happens-in-parallel.https.html.headers": [ "4b06ac7cc63e8af6f7d6a882b960184c9a4ea281", [] @@ -525631,6 +526261,14 @@ "b73781244ebd3fcad445f0227e33411ac08a5205", [] ] + }, + "tentative": { + "resources": { + "shared-worker-memory.js": [ + "b1504f38c504c0003d2aa179cfae5702ab318563", + [] + ] + } } }, "worklets": { @@ -568178,6 +568816,13 @@ {} ] ], + "containertiming-with-child-ignore-and-child-img.html": [ + "b4fa9754c1025e255a678d298d3c3db1c30c2b4c", + [ + null, + {} + ] + ], "containertiming-with-child-img.html": [ "03f0e113902d0d4117a38870dfd22defe99c4653", [ @@ -568192,6 +568837,20 @@ {} ] ], + "containertiming-with-ignore-and-child-img.html": [ + "20e9e4a92180d36c3a4130139330ea3229227105", + [ + null, + {} + ] + ], + "ignore-with-containertiming-and-child-img.html": [ + "841b4441d4df846317c246a461022cffe875fab3", + [ + null, + {} + ] + ], "img-not-child-of-container-timing.html": [ "751342a7ceb1eaa2a98d1c07dc4000c34d14e4fd", [ @@ -568648,7 +569307,7 @@ ] ], "default-src-sri_hash.sub.html": [ - "87fce5961fd1854303377ee939b21b6275b312cf", + "87389c306a53fdffa9806ba05f08a097713bcc37", [ null, {} @@ -573246,7 +573905,7 @@ ] ], "script-src-sri_hash.sub.html": [ - "9216e2b0d4971fc46d0010e8dfa7375845187a8d", + "e290911183d0b9a5dccf4a6a2eaa3b12ee25c682", [ null, {} @@ -573351,7 +574010,7 @@ ] ], "script-src-strict_dynamic_parser_inserted.html": [ - "c5e33dc4253dbf3ce2b0c6cb2fca4b0306d68244", + "9a8ad7a4ef2b5592af70d4dcc56f291e75da8e1b", [ null, {} @@ -575838,7 +576497,7 @@ ] ], "cookieStore_special_names.https.any.js": [ - "e2a3df7fe33f3d4325cb1f602d5582dba97da627", + "1e12674a7f7ce9b1fbc5aa46e53be9c6bc08c084", [ "cookie-store/cookieStore_special_names.https.any.html", { @@ -575926,7 +576585,7 @@ ] ], "encoding.https.any.js": [ - "941639bdaec01d0eb619a5850b1d878bdf77f695", + "f5d2ca15e717a0837f1e08031ab682db5aa965ea", [ "cookie-store/encoding.https.any.html", { @@ -575967,7 +576626,7 @@ ] ], "httponly_cookies.https.window.js": [ - "605e94e67440aaedbcaa39f185270fe77b316ad3", + "836f47da3f6e0f8f2c89445d1b2fbdfdf9ddc9e6", [ "cookie-store/httponly_cookies.https.window.html", { @@ -579951,7 +580610,7 @@ ] ], "anchor-scope-basic.html": [ - "47cb3b8d86a106f37af3e32149b79fbd9c8c2056", + "ffe3b45ba0de4d119576bc8b2d307ed55c9ea7f0", [ null, {} @@ -585012,7 +585671,7 @@ ] ], "parsing.html": [ - "2447891f2c4b163cc30eaaa2c6542d9a80a2b4cf", + "688043039de4c9a3d9ee58480a3185509ce72814", [ null, {} @@ -586103,6 +586762,13 @@ {} ] ], + "style-query-registered-custom-rem-change.html": [ + "33808fbe198935daf3ad4efc769483cfbc625c8e", + [ + null, + {} + ] + ], "style-query-unset-on-root.html": [ "89c5cc038a8f1fcee5f0fd0de116c679c666788b", [ @@ -595126,8 +595792,15 @@ {} ] ], + "HighlightRegistry-highlightsFromPoint-ranges.html": [ + "24cf8aa6dfec302877e445ebf81dca76357cea06", + [ + null, + {} + ] + ], "HighlightRegistry-highlightsFromPoint.html": [ - "5bb81bea69ac5960db16e3f9ec3bb208f43a7200", + "5b4e7704a4df5c01d3effa1c519e39b450bbe30a", [ null, {} @@ -596807,7 +597480,7 @@ ] ], "clip-path-interpolation-shape.html": [ - "6d85c2a06b491bbc54e7cfba6705fd9b6af2098f", + "f725e1fc6fa0cbde5928c1e45e5e7c5f72b1a7dd", [ null, {} @@ -597020,7 +597693,7 @@ ] ], "clip-path-shape-parsing.html": [ - "5a4c7415bb40632989c87ee1fbe51540f94af8e2", + "b889ee018056c5db7611cc70de823482ed5cac36", [ null, {} @@ -597895,7 +598568,7 @@ ] ], "column-rule-color-invalid.html": [ - "015defb7560038b03fc4d5f18a04a1d0e094a03d", + "da8dba0a73c9c7829766cd2fad39bfa79fbc6c40", [ null, {} @@ -597937,7 +598610,7 @@ ] ], "column-rule-style-invalid.html": [ - "db367c273f4f2e4bb59893d56388f119cb90ea40", + "e8f2ab60c47748c4a8088024bbcf30eb2c9c16b2", [ null, {} @@ -597965,7 +598638,7 @@ ] ], "column-rule-width-invalid.html": [ - "0bdbbecb8cada68b8243566b265029ee98c55571", + "77f55e09d931cf91618cc7be5a9a9f46c85960dc", [ null, {} @@ -605455,6 +606128,13 @@ null, {} ] + ], + "from-element.tentative.html": [ + "fe99ccb23d9c279011e15f66cbbe20cd87e31568", + [ + null, + {} + ] ] } }, @@ -612667,14 +613347,14 @@ ] ], "column-rule-style.html": [ - "8e56f62171485661197a617bfe688e4f4e922569", + "7098270a3921df847c907842cd7b64cea43d261b", [ null, {} ] ], "column-rule-width.html": [ - "bd3c0ac8f43d1770d04e46913066c6feddee8a08", + "8f09d1cb45aa55c8677810a5911160609514372e", [ null, {} @@ -615461,7 +616141,7 @@ ] ], "if-conditionals.html": [ - "caead7864d550f8732eff919c1b555c8f759508d", + "f6d981798ae7a03f97b4fd089ee02141c7f90813", [ null, {} @@ -615925,6 +616605,13 @@ {} ] ], + "sibling-function-container-query-invalidation.html": [ + "c0d6d913af049d6d316ab664e0d93556bff01e7c", + [ + null, + {} + ] + ], "sibling-function-container-query.html": [ "addcf0b2d48f5c444a9f93264a2136342c4b48d6", [ @@ -615982,7 +616669,7 @@ ] ], "sibling-index-keyframe-registered-properties-dynamic.html": [ - "77af5434a1c4903928194bec4174745a3bd1efeb", + "ac2ed1a8af1b1cddbae8ce18f7afaa7897466a67", [ null, {} @@ -616521,7 +617208,7 @@ }, "css-view-transitions": { "auto-name-get-animations.html": [ - "0442255542c0349438ef7e951da7c6b47928c858", + "b684349a5f9caf390d0a376727dda85602104f28", [ null, {} @@ -617243,6 +617930,13 @@ ] ], "zoom": { + "length-implicit-and-explicit-inheritance.html": [ + "003c7b61c0909f494f02a68e20fad2c152b96a34", + [ + null, + {} + ] + ], "parsing": { "zoom-computed-with-sign-expression.html": [ "8029fd3a65e542749792a48100161f18fd25fee9", @@ -621223,7 +621917,7 @@ ] ], "offset-path-interpolation-008.html": [ - "5fb7c7c333c89f4107e2824390c73862be8107d0", + "ff7d4a108c77f65363d91d9e4bc52eed500913c1", [ null, {} @@ -621365,14 +622059,14 @@ ] ], "offset-path-shape-computed.html": [ - "c9ecc3acb06c065913f8b7538fdf81bff6c802df", + "6ced1ad395ad46206bf63da5ec871d5481185312", [ null, {} ] ], "offset-path-shape-parsing.html": [ - "013cea2c8211d97a5e90c42379cf5aadfe8b59fd", + "4a3d9f169151c3d9a9f7f997410405ad36de2410", [ null, {} @@ -630517,6 +631211,13 @@ {} ] ], + "fn-id.html": [ + "617ff7216d84d56f8cef3f8ca08e902dd67f487d", + [ + null, + {} + ] + ], "fn-lang.html": [ "1fbd0a2ee4d419275c6d78f54e3425135cf838a1", [ @@ -633824,13 +634525,6 @@ } ] ], - "move-inserted-node-from-DOMNodeInserted-during-exec-command-insertHTML.html": [ - "41e012a62e9617f372f85d0a0cedefe8ad42fbd6", - [ - null, - {} - ] - ], "no-beforeinput-when-no-selection.html": [ "098a95863a606393502d4e2fc517fcb8ad144d35", [ @@ -661675,7 +662369,7 @@ "content-encoding": { "br": { "bad-br-body.https.any.js": [ - "43ea90a336cd04df56b4f29f57182d2860481938", + "af5df674da6dcf957d0c5fb69d3538a12096c005", [ "fetch/content-encoding/br/bad-br-body.https.any.html", { @@ -661799,7 +662493,7 @@ }, "gzip": { "bad-gzip-body.any.js": [ - "17bc1261a3f5c36a9797c5a171990c522cfe7598", + "77a183f408b34c75eb3d3e0a1635daad79ff1355", [ "fetch/content-encoding/gzip/bad-gzip-body.any.html", { @@ -661956,7 +662650,7 @@ }, "zstd": { "bad-zstd-body.https.any.js": [ - "3f32e4dfba786511d845c3e913e59b818d0f292b", + "c59980c2c6fb694080417cdd6db1b237f70715b2", [ "fetch/content-encoding/zstd/bad-zstd-body.https.any.html", { @@ -667031,29 +667725,6 @@ } ] ], - "mixed-content-fetch.tentative.https.window.js": [ - "dbae5193b5cb02e3b0eba3531483aac372ba8700", - [ - "fetch/private-network-access/mixed-content-fetch.tentative.https.window.html", - { - "script_metadata": [ - [ - "script", - "/common/utils.js" - ], - [ - "script", - "resources/support.sub.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], "nested-worker.tentative.https.window.js": [ "3eeb435badb2d00404e0e214e1d42c4be2817f8a", [ @@ -667414,185 +668085,6 @@ } ] ], - "window-open-existing.tentative.https.window.js": [ - "6a2a624fc8032d03b626109ee7f825f7acf5874c", - [ - "fetch/private-network-access/window-open-existing.tentative.https.window.html?include=from-local", - { - "script_metadata": [ - [ - "script", - "/common/subset-tests-by-key.js" - ], - [ - "script", - "/common/dispatcher/dispatcher.js" - ], - [ - "script", - "/common/utils.js" - ], - [ - "script", - "resources/support.sub.js" - ], - [ - "timeout", - "long" - ], - [ - "variant", - "?include=from-local" - ], - [ - "variant", - "?include=from-private" - ], - [ - "variant", - "?include=from-public" - ], - [ - "variant", - "?include=from-treat-as-public" - ] - ], - "timeout": "long" - } - ], - [ - "fetch/private-network-access/window-open-existing.tentative.https.window.html?include=from-private", - { - "script_metadata": [ - [ - "script", - "/common/subset-tests-by-key.js" - ], - [ - "script", - "/common/dispatcher/dispatcher.js" - ], - [ - "script", - "/common/utils.js" - ], - [ - "script", - "resources/support.sub.js" - ], - [ - "timeout", - "long" - ], - [ - "variant", - "?include=from-local" - ], - [ - "variant", - "?include=from-private" - ], - [ - "variant", - "?include=from-public" - ], - [ - "variant", - "?include=from-treat-as-public" - ] - ], - "timeout": "long" - } - ], - [ - "fetch/private-network-access/window-open-existing.tentative.https.window.html?include=from-public", - { - "script_metadata": [ - [ - "script", - "/common/subset-tests-by-key.js" - ], - [ - "script", - "/common/dispatcher/dispatcher.js" - ], - [ - "script", - "/common/utils.js" - ], - [ - "script", - "resources/support.sub.js" - ], - [ - "timeout", - "long" - ], - [ - "variant", - "?include=from-local" - ], - [ - "variant", - "?include=from-private" - ], - [ - "variant", - "?include=from-public" - ], - [ - "variant", - "?include=from-treat-as-public" - ] - ], - "timeout": "long" - } - ], - [ - "fetch/private-network-access/window-open-existing.tentative.https.window.html?include=from-treat-as-public", - { - "script_metadata": [ - [ - "script", - "/common/subset-tests-by-key.js" - ], - [ - "script", - "/common/dispatcher/dispatcher.js" - ], - [ - "script", - "/common/utils.js" - ], - [ - "script", - "resources/support.sub.js" - ], - [ - "timeout", - "long" - ], - [ - "variant", - "?include=from-local" - ], - [ - "variant", - "?include=from-private" - ], - [ - "variant", - "?include=from-public" - ], - [ - "variant", - "?include=from-treat-as-public" - ] - ], - "timeout": "long" - } - ] - ], "window-open-existing.tentative.window.js": [ "5a6cd4c5cfd20c931a37c4f98524a4a59c0d07c9", [ @@ -683042,6 +683534,13 @@ {} ] ], + "focus-contenteditable-element-in-iframe-scroll-into-view.html": [ + "1c03382201eb05785a003d068bf0e14150e10608", + [ + null, + {} + ] + ], "focus-double-sync-calls.html": [ "8d5f5c8a79fc6c65556e151fed9610a9cb915f98", [ @@ -733174,7 +733673,7 @@ ] ], "image-decode-path-changes-svg.tentative.html": [ - "1bc53a1f18e56fbd2f586b91cf78e00c846eecbb", + "3ef59c37a8500f64bc60011174560f4aca0bea5d", [ null, { @@ -733210,7 +733709,7 @@ ] ], "image-decode-with-quick-attach-svg.tentative.html": [ - "0fc49e603606e9233d0b3ae59757aec149c8aaf2", + "fbc7143eceead959bc34270b55ad850044215ece", [ null, { @@ -733590,7 +734089,7 @@ ] ], "naturalWidth-naturalHeight-unavailable.tentative.html": [ - "df9eb374b5adc003c93830ab4605b2adad0ae84d", + "ae6fa0e432853d111aa63bd87f43206acec86024", [ null, {} @@ -738083,8 +738582,8 @@ } ] ], - "negative-offset-and-margin.tentative.html": [ - "0b3d8dc98812e01e7255cc166fa0bc0704f0eac4", + "negative-offset.tentative.html": [ + "c1424ad9cc80e27fac9f0693defd87dd273ad2e2", [ null, {} @@ -738098,7 +738597,7 @@ ] ], "no-focus.tentative.html": [ - "9646788518323b331ac7278dd0afb754392ef6be", + "1bf29634605cc55210fef4a04cfaaa2c436fcd09", [ null, { @@ -739157,34 +739656,6 @@ {} ] ], - "042.html": [ - "df3a2f88f29f2e8035d8c778c3397ad464688e18", - [ - null, - {} - ] - ], - "043.html": [ - "bcfd90cba47880efa48f9e809f37209f5f024dd6", - [ - null, - {} - ] - ], - "044.html": [ - "8d412079e45f9f8a3d074d707db39a55e1d8b946", - [ - null, - {} - ] - ], - "045.html": [ - "254e0d13662786d8542d03de3547b39ecf684ede", - [ - null, - {} - ] - ], "046.html": [ "4f145d63e1d619df2df429ec6fd713e77e303cb3", [ @@ -739243,20 +739714,6 @@ {} ] ], - "054.html": [ - "29ede23414ec57950717a05e375cbc15547c0b4d", - [ - null, - {} - ] - ], - "055.html": [ - "c837d78174b108d8b90cca4dccbc91bef8e1efad", - [ - null, - {} - ] - ], "056.html": [ "e2d0868034e1b243e610b3e3afdea18d78c418c8", [ @@ -740212,7 +740669,7 @@ ] ], "invalid-content-type.any.js": [ - "d15fa3f1b7090dc0e309097c497dcd3626301c31", + "d0bb6aa9fb17fe49d85bef83486edf4148ac970d", [ "html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.html", { @@ -740381,7 +740838,7 @@ ] ], "valid-content-type.html": [ - "3232b84d271e0faa49fd600eac9f4394db7f5630", + "fdeba93ba893176df88fe69f54606b4d01020436", [ null, {} @@ -743333,6 +743790,13 @@ "timeout": "long" } ] + ], + "source-attribute-retargeting.tentative.html": [ + "885b75a3387a8f61f8f25fdd93d60fe3027b5599", + [ + null, + {} + ] ] }, "interest-target": { @@ -771868,6 +772332,15 @@ } ] ], + "get-persistendeviceid-from-pointer-mouse-event.tentative.html": [ + "66fb63d54d1acedc17e9a522eefebe0fba76f943", + [ + null, + { + "testdriver": true + } + ] + ], "pointer-event-has-persistentdeviceid-from-pointer-event-init.tentative.html": [ "c3fc4270f6177c94ccd191a29d86b77a220f3577", [ @@ -787247,6 +787720,13 @@ null, {} ] + ], + "zoom.html": [ + "77b4bc49fa7e8e4d13083f8ef97ced833e627a85", + [ + null, + {} + ] ] }, "resource-timing": { @@ -787418,7 +787898,7 @@ ] ], "content-encoding.https.html": [ - "0d67bfc7d4f9a9c471272a8a475655d1c5225552", + "80473552f08b0c5f857533bdebf7a168283d5953", [ null, {} @@ -790732,7 +791212,7 @@ ] ], "animation-trigger-repeat.tentative.html": [ - "cfbe9d3c9334148789d4cebc7a01a2f9e848b22d", + "6c01e762e5acd18a1def36673c93d7fcdedf4964", [ null, {} @@ -796663,7 +797143,7 @@ ] ], "HighlightRegistry-highlightsFromPoint.html": [ - "5244f923e3404064987ce16d0fd1e9215ad768c3", + "4098bc5a9941f23405d754e786351320e14125d6", [ null, {} @@ -799849,7 +800329,7 @@ ] ], "first-interaction-not-softnav.tentative.html": [ - "e02620218368d71ff10196c9ff75a13a361f5d90", + "2c9e2aa7c014025ca409da94172d6e0d61d106d7", [ null, { @@ -799893,15 +800373,6 @@ } ] ], - "innertext.tentative.html": [ - "7716488f25a08ea62635fceec679d97650d1f383", - [ - null, - { - "testdriver": true - } - ] - ], "interaction-with-paint-before-back.tentative.html": [ "effccbfd762434c84b672173b122b07272542fe5", [ @@ -800095,7 +800566,7 @@ ] ], "dom.html": [ - "66d23b22788c4749d7b990b89b0cef612872f5f4", + "2e3c3809df68ba4093247e2d4e3fe114f8c9f729", [ null, { @@ -800120,6 +800591,15 @@ "testdriver": true } ] + ], + "window-open-cross-scheduling.html": [ + "1a41be6ddd2d716c4012b5524e8a30b9821ec3e3", + [ + null, + { + "testdriver": true + } + ] ] } }, @@ -800559,6 +801039,15 @@ {} ] ], + "no-prefetch-for-post.https.html": [ + "7739f4f8c7105b2c4e9ed4671081b00d0c0b8c6e", + [ + null, + { + "timeout": "long" + } + ] + ], "no-vary-search": { "prefetch-single-with-hint.https.html": [ "f2d8b3090e1f8447f86bd62a6f24ca9daae06ec7", @@ -801551,6 +802040,15 @@ } ] ], + "headers.https.html": [ + "2ef6b5ce072866d3c88ce7a86fcea6436de3364a", + [ + null, + { + "timeout": "long" + } + ] + ], "iframe-added-post-activation.https.html": [ "d22b511e108d8b7c7f0b63f28e5bf485eca98758", [ @@ -821765,14 +822263,14 @@ ] ], "block-text-node-insertion-into-script-element.html": [ - "65b40b933ff8417ad5147ce29d68bc19707bc0b9", + "1a1256d05a8c996d078ca287950660fd5d1e9071", [ null, {} ] ], "block-text-node-insertion-into-svg-script-element.html": [ - "f4ff24350355a29f033489d51bf4a021d9673dd2", + "18c6af8f5efcf72c11876b4f2740cdddd5cf1c84", [ null, {} @@ -822768,13 +823266,6 @@ }, "legacy-domevents-tests": { "approved": { - "ProcessingInstruction.DOMCharacterDataModified.html": [ - "2da0a389e2e3bc51861fef752b11a629203897d0", - [ - null, - {} - ] - ], "dispatchEvent.click.checkbox.html": [ "8cb548f84c60eb6b528c1049884649b26c4f18ba", [ @@ -822782,13 +823273,6 @@ {} ] ], - "domnodeinserted.html": [ - "e5064d8d46cd9aad4768aa81dacb18b989e2c993", - [ - null, - {} - ] - ], "stopImmediatePropagation.effect.html": [ "a414d60298acece6dce5d970e6f0448a99fd65da", [ @@ -826096,6 +826580,53 @@ } ] ], + "urlpattern-generate.tentative.any.js": [ + "1f6962942d88f88684c5302175202e0278d3d971", + [ + "urlpattern/urlpattern-generate.tentative.any.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ] + ] + } + ], + [ + "urlpattern/urlpattern-generate.tentative.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ] + ] + } + ], + [ + "urlpattern/urlpattern-generate.tentative.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ] + ] + } + ], + [ + "urlpattern/urlpattern-generate.tentative.any.worker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ] + ] + } + ] + ], "urlpattern-hasregexpgroups.any.js": [ "33133d2511b065ca94cc5e793066cc8111b4d6e6", [ @@ -855415,7 +855946,7 @@ ] ], "cumulative_sum.https.any.js": [ - "85e1ab427d208f76aae62bff8c603b0d891f7180", + "34a625152b26a3183a7cd62c38883a684ac93908", [ "webnn/conformance_tests/cumulative_sum.https.any.html?cpu", { @@ -859171,7 +859702,7 @@ ] ], "linear.https.any.js": [ - "9231aaf9ecad0996b8dfb9530c4a7f55b2aa8e06", + "1f13fe170d46fa157035bd6e14de6eb68462c7a4", [ "webnn/conformance_tests/linear.https.any.html?cpu", { @@ -861604,7 +862135,7 @@ ] ], "qdq_subgraph.https.any.js": [ - "ac384c917b33dda2243779a396d0d557c40003dc", + "996a6b472c5689bc082388d5c267d2f5fe460080", [ "webnn/conformance_tests/qdq_subgraph.https.any.html?cpu", { @@ -865945,7 +866476,7 @@ ] ], "subgraph.https.any.js": [ - "9b21d6e4f9453fb72c3f7a6850c5690cc9ed87cf", + "8a0b7faa92f938282c7a6bb02ac61ef6730f021d", [ "webnn/conformance_tests/subgraph.https.any.html?cpu", { @@ -882776,7 +883307,7 @@ ] ], "RTCConfiguration-iceServers.html": [ - "bc7831361ab5f417b46a507b0e5977bef9bedd49", + "65a6015f52a7233260ab8405fb43bc347fa0ff4b", [ null, {} @@ -884735,7 +885266,7 @@ ] ], "RTCEncodedAudioFrame-metadata.https.html": [ - "df4577c5614a82afd7b02d988d0f15caa3b9e848", + "1e148fe1b29a167e6451162125b7390151ec90bd", [ null, { @@ -897599,7 +898130,7 @@ ] ], "remote-close.any.js": [ - "b7fd321914a4e6f9bf70d431bca591a7c5460675", + "c3e7ad5f9fbef1494ed7594dc7d497e9f867361a", [ "websockets/stream/tentative/remote-close.any.html?default", { @@ -898019,6 +898550,429 @@ ] } ] + ], + "write.any.js": [ + "43af7da614c675fcc0571d7edff3515a92774caf", + [ + "websockets/stream/tentative/write.any.html?default", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.html?wpt_flags=h2", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.html?wss", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.serviceworker.html?default", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.serviceworker.html?wpt_flags=h2", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.serviceworker.html?wss", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.sharedworker.html?default", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.sharedworker.html?wpt_flags=h2", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.sharedworker.html?wss", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.worker.html?default", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.worker.html?wpt_flags=h2", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ], + [ + "websockets/stream/tentative/write.any.worker.html?wss", + { + "script_metadata": [ + [ + "script", + "../../constants.sub.js" + ], + [ + "script", + "resources/url-constants.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "global", + "window,worker" + ], + [ + "variant", + "?default" + ], + [ + "variant", + "?wss" + ], + [ + "variant", + "?wpt_flags=h2" + ] + ] + } + ] ] } }, @@ -905196,6 +906150,15 @@ {} ] ], + "tentative": { + "SharedWorker-extendedLifetime.html": [ + "3c76eddd7647991ae171b4d5e4766af5d156dd9a", + [ + null, + {} + ] + ] + }, "worker-performance.worker.js": [ "c913b2e7375067c1a21bdc655f394b5c27bc5aed", [ diff --git a/tests/wpt/meta/content-security-policy/connect-src/connect-src-syncxmlhttprequest-redirect-to-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/connect-src/connect-src-syncxmlhttprequest-redirect-to-blocked.sub.html.ini deleted file mode 100644 index e6156eab928..00000000000 --- a/tests/wpt/meta/content-security-policy/connect-src/connect-src-syncxmlhttprequest-redirect-to-blocked.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[connect-src-syncxmlhttprequest-redirect-to-blocked.sub.html] - [Expecting logs: ["PASS Sync XMLHttpRequest.send() did not follow the disallowed redirect.","TEST COMPLETE","violated-directive=connect-src"\]] - expected: FAIL diff --git a/tests/wpt/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-redirect-to-blocked.sub.html.ini b/tests/wpt/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-redirect-to-blocked.sub.html.ini deleted file mode 100644 index 9b86b6b2d9c..00000000000 --- a/tests/wpt/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-redirect-to-blocked.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[connect-src-xmlhttprequest-redirect-to-blocked.sub.html] - [Expecting logs: ["PASS XMLHttpRequest.send() did not follow the disallowed redirect.","TEST COMPLETE","violated-directive=connect-src"\]] - 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 5891a18681e..0c6a81792db 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,6 +1,3 @@ [script-tag.http.html] [Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.] expected: FAIL - - [Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.: securitypolicyviolation] - 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 699a0dd6238..b5c643337e2 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,6 +1,3 @@ [script-tag.https.html] [Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.] expected: FAIL - - [Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.: securitypolicyviolation] - 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 5891a18681e..0c6a81792db 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,6 +1,3 @@ [script-tag.http.html] [Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.] expected: FAIL - - [Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.: securitypolicyviolation] - 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 699a0dd6238..b5c643337e2 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,6 +1,3 @@ [script-tag.https.html] [Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.] expected: FAIL - - [Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.: securitypolicyviolation] - expected: FAIL diff --git a/tests/wpt/meta/content-security-policy/generic/wildcard-host-part.sub.window.js.ini b/tests/wpt/meta/content-security-policy/generic/wildcard-host-part.sub.window.js.ini deleted file mode 100644 index 7770d4e4454..00000000000 --- a/tests/wpt/meta/content-security-policy/generic/wildcard-host-part.sub.window.js.ini +++ /dev/null @@ -1,2 +0,0 @@ -[wildcard-host-part.sub.window.html] - expected: CRASH diff --git a/tests/wpt/meta/content-security-policy/inside-worker/dedicatedworker-connect-src.html.ini b/tests/wpt/meta/content-security-policy/inside-worker/dedicatedworker-connect-src.html.ini index ad01d630c28..72db221f4dd 100644 --- a/tests/wpt/meta/content-security-policy/inside-worker/dedicatedworker-connect-src.html.ini +++ b/tests/wpt/meta/content-security-policy/inside-worker/dedicatedworker-connect-src.html.ini @@ -1,7 +1,4 @@ [dedicatedworker-connect-src.html] - [Same-origin => cross-origin 'fetch()' in http: with connect-src 'self'] - expected: FAIL - [Reports match in http: with connect-src 'self'] expected: FAIL 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 66a2ee93f3b..f160ad3d25d 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,10 +1,3 @@ [report-original-url.sub.html] - expected: TIMEOUT - [Block after redirect, same-origin = original URL in report] - expected: TIMEOUT - - [Block after redirect, cross-origin = original URL in report] - expected: TIMEOUT - [Violation report status OK.] expected: FAIL diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html.ini deleted file mode 100644 index 95cb135df4e..00000000000 --- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[img-src-redirect.sub.html] - [The blocked URI in the security policy violation event should be the original URI before redirects.] - expected: FAIL diff --git a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html.ini b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html.ini index 11dc161d87a..34de05fc1cc 100644 --- a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html.ini +++ b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html.ini @@ -78,3 +78,6 @@ [corner-shape-render-fuzzy.html?border-radius=50%&corner-top-right-shape=scoop&corner-bottom-left-shape=scoop&corner-top-left-shape=notch&corner-bottom-right-shape=notch&border-width=10px] expected: FAIL + +[corner-shape-render-fuzzy.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px] + expected: FAIL diff --git a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html.ini b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html.ini index 68682a3e807..1fda8aa0448 100644 --- a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html.ini +++ b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html.ini @@ -37,9 +37,6 @@ [corner-shape-render-precise.html?corner-top-left-shape=bevel&border-width=10px&border-color=black] expected: FAIL -[corner-shape-render-precise.html?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel] - expected: FAIL - [corner-shape-render-precise.html?corner-shape=superellipse(8)&border-radius=10px&box-shadow=10px 10px 0 10px black] expected: FAIL @@ -90,3 +87,6 @@ [corner-shape-render-precise.html?corner-shape=superellipse(-2)&border-top-left-radius=40%&border-width=20px] expected: FAIL + +[corner-shape-render-precise.html?corner-shape=notch&border-radius=30px&border-width=30px] + expected: FAIL diff --git a/tests/wpt/meta/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html.ini new file mode 100644 index 00000000000..ee69bd41b83 --- /dev/null +++ b/tests/wpt/meta/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html.ini @@ -0,0 +1,3 @@ +[style-query-registered-custom-rem-change.html] + [Changing the :root font-size to 10px makes 1rem * 10 evaluate to 100px] + expected: FAIL diff --git a/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-040.html.ini b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-040.html.ini new file mode 100644 index 00000000000..961df8f5b9b --- /dev/null +++ b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-040.html.ini @@ -0,0 +1,2 @@ +[grid-gap-decorations-040.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-masking/clip-path/clip-path-shape-011.html.ini b/tests/wpt/meta/css/css-masking/clip-path/clip-path-shape-011.html.ini new file mode 100644 index 00000000000..7598b3ef8ec --- /dev/null +++ b/tests/wpt/meta/css/css-masking/clip-path/clip-path-shape-011.html.ini @@ -0,0 +1,2 @@ +[clip-path-shape-011.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-overflow/overflow-video.html.ini b/tests/wpt/meta/css/css-overflow/overflow-video.html.ini deleted file mode 100644 index 1d0a9d754d6..00000000000 --- a/tests/wpt/meta/css/css-overflow/overflow-video.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[overflow-video.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html.ini b/tests/wpt/meta/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html.ini new file mode 100644 index 00000000000..9682a816732 --- /dev/null +++ b/tests/wpt/meta/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html.ini @@ -0,0 +1,2 @@ +[responsive-iframe-cross-origin.sub.tentative.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/responsive-iframe.tentative.html.ini b/tests/wpt/meta/css/css-sizing/responsive-iframe.tentative.html.ini new file mode 100644 index 00000000000..768b6a9e977 --- /dev/null +++ b/tests/wpt/meta/css/css-sizing/responsive-iframe.tentative.html.ini @@ -0,0 +1,2 @@ +[responsive-iframe.tentative.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/table-cell-overflow-auto-scrolled.html.ini b/tests/wpt/meta/css/css-tables/table-cell-overflow-auto-scrolled.html.ini new file mode 100644 index 00000000000..55805c45ee2 --- /dev/null +++ b/tests/wpt/meta/css/css-tables/table-cell-overflow-auto-scrolled.html.ini @@ -0,0 +1,2 @@ +[table-cell-overflow-auto-scrolled.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-text/text-autospace/text-autospace-vs-001.html.ini b/tests/wpt/meta/css/css-text/text-autospace/text-autospace-vs-001.html.ini new file mode 100644 index 00000000000..04071c4d8b3 --- /dev/null +++ b/tests/wpt/meta/css/css-text/text-autospace/text-autospace-vs-001.html.ini @@ -0,0 +1,2 @@ +[text-autospace-vs-001.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-text/word-break/word-break-keep-all-u002d.html.ini b/tests/wpt/meta/css/css-text/word-break/word-break-keep-all-u002d.html.ini new file mode 100644 index 00000000000..5de432ffdee --- /dev/null +++ b/tests/wpt/meta/css/css-text/word-break/word-break-keep-all-u002d.html.ini @@ -0,0 +1,2 @@ +[word-break-keep-all-u002d.html] + expected: FAIL diff --git a/tests/wpt/meta/css/css-values/if-conditionals.html.ini b/tests/wpt/meta/css/css-values/if-conditionals.html.ini index aa2285ad06e..25afac97880 100644 --- a/tests/wpt/meta/css/css-values/if-conditionals.html.ini +++ b/tests/wpt/meta/css/css-values/if-conditionals.html.ini @@ -442,3 +442,126 @@ [CSS Values and Units Test: CSS inline if() function 147] expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 148] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 149] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 150] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 151] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 152] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 153] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 154] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 155] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 156] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 157] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 158] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 159] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 160] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 161] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 162] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 163] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 164] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 165] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 166] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 167] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 168] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 169] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 170] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 171] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 172] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 173] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 174] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 175] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 176] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 177] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 178] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 179] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 180] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 181] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 182] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 183] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 184] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 185] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 186] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 187] + expected: FAIL + + [CSS Values and Units Test: CSS inline if() function 188] + expected: FAIL diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-function-container-query-invalidation.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-function-container-query-invalidation.html.ini new file mode 100644 index 00000000000..4d74ed1e63c --- /dev/null +++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-function-container-query-invalidation.html.ini @@ -0,0 +1,12 @@ +[sibling-function-container-query-invalidation.html] + [sibling-index() in @container width query matching after removal] + expected: FAIL + + [sibling-count() in @container width query matching after removal] + expected: FAIL + + [sibling-index() in @container style() query matching after removal] + expected: FAIL + + [sibling-count() in @container style() query matching after removal] + expected: FAIL diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini index 807d5e54ab4..4be76b217d3 100644 --- a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini +++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini @@ -52,3 +52,9 @@ [Removing a preceding sibling of #target reduces the sibling-index() for --color] expected: FAIL + + [Initially, the sibling-index() is 3 for --list] + expected: FAIL + + [Removing a preceding sibling of #target reduces the sibling-index() for --list] + expected: FAIL diff --git a/tests/wpt/meta/custom-elements/registries/idlharness.window.js.ini b/tests/wpt/meta/custom-elements/registries/idlharness.window.js.ini index 44fbd51d205..e033f991a62 100644 --- a/tests/wpt/meta/custom-elements/registries/idlharness.window.js.ini +++ b/tests/wpt/meta/custom-elements/registries/idlharness.window.js.ini @@ -1,3 +1,42 @@ [idlharness.window.html] [idl_test setup] expected: FAIL + + [idl_test validation] + expected: FAIL + + [Partial interface CustomElementRegistry: member names are unique] + expected: FAIL + + [Partial interface HTMLTemplateElement: member names are unique] + expected: FAIL + + [Partial interface Element: member names are unique] + expected: FAIL + + [Partial dictionary ShadowRootInit: member names are unique] + expected: FAIL + + [Partial dictionary ElementCreationOptions: member names are unique] + expected: FAIL + + [Document includes DocumentOrShadowRoot: member names are unique] + expected: FAIL + + [ShadowRoot includes DocumentOrShadowRoot: member names are unique] + expected: FAIL + + [HTMLTemplateElement interface: attribute shadowRootCustomElementRegistry] + expected: FAIL + + [CustomElementRegistry interface: operation initialize(Node)] + expected: FAIL + + [Document interface: attribute customElementRegistry] + expected: FAIL + + [ShadowRoot interface: attribute customElementRegistry] + expected: FAIL + + [Element interface: attribute customElementRegistry] + expected: FAIL diff --git a/tests/wpt/meta/dom/ranges/Range-in-shadow-after-the-shadow-removed.html.ini b/tests/wpt/meta/dom/ranges/Range-in-shadow-after-the-shadow-removed.html.ini deleted file mode 100644 index b2003b5c788..00000000000 --- a/tests/wpt/meta/dom/ranges/Range-in-shadow-after-the-shadow-removed.html.ini +++ /dev/null @@ -1,14 +0,0 @@ -[Range-in-shadow-after-the-shadow-removed.html?mode=closed] - [Range in shadow should stay in the shadow after the host is removed] - expected: FAIL - - [Range in shadow should stay in the shadow after the host parent is removed] - expected: FAIL - - -[Range-in-shadow-after-the-shadow-removed.html?mode=open] - [Range in shadow should stay in the shadow after the host is removed] - expected: FAIL - - [Range in shadow should stay in the shadow after the host parent is removed] - expected: FAIL diff --git a/tests/wpt/meta/domxpath/fn-lang.html.ini b/tests/wpt/meta/domxpath/fn-lang.html.ini deleted file mode 100644 index 31754463dcc..00000000000 --- a/tests/wpt/meta/domxpath/fn-lang.html.ini +++ /dev/null @@ -1,21 +0,0 @@ -[fn-lang.html] - [lang("en"): <root><match lang="en"></match></root>] - expected: FAIL - - [lang("en"): <root><match lang="EN"></match></root>] - expected: FAIL - - [lang("en"): <root><match lang="en-us"></match></root>] - expected: FAIL - - [lang("en"): <root><unmatch></unmatch></root>] - expected: FAIL - - [lang("ja"): <root lang="ja"><match></match></root>] - expected: FAIL - - [lang("ja"): <root lang="ja-jp"><unmatch lang="ja_JP"></unmatch></root>] - expected: FAIL - - [lang("ko"): <root><unmatch lang="Ko"></unmatch></root>] - expected: FAIL diff --git a/tests/wpt/meta/domxpath/node-sets.html.ini b/tests/wpt/meta/domxpath/node-sets.html.ini deleted file mode 100644 index 856f22dd655..00000000000 --- a/tests/wpt/meta/domxpath/node-sets.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[node-sets.html] - [| operator should evaluate both sides of expressions with the same context node] - expected: FAIL diff --git a/tests/wpt/meta/domxpath/text-html-attributes.html.ini b/tests/wpt/meta/domxpath/text-html-attributes.html.ini index 803f418282a..7257f61a118 100644 --- a/tests/wpt/meta/domxpath/text-html-attributes.html.ini +++ b/tests/wpt/meta/domxpath/text-html-attributes.html.ini @@ -1,13 +1,7 @@ [text-html-attributes.html] - [Select html element based on attribute] - expected: FAIL - [Select html element based on attribute mixed case] expected: FAIL - [Select both HTML and SVG elements based on attribute] - expected: FAIL - [Select HTML element with non-ascii attribute 1] expected: FAIL @@ -23,9 +17,6 @@ [Select both HTML and SVG elements based on mixed case attribute] expected: FAIL - [Select SVG elements with refX attribute] - expected: FAIL - [Select SVG element with non-ascii attribute 1] expected: FAIL diff --git a/tests/wpt/meta/domxpath/xml_xpath_runner.html.ini b/tests/wpt/meta/domxpath/xml_xpath_runner.html.ini deleted file mode 100644 index e7d698afb6b..00000000000 --- a/tests/wpt/meta/domxpath/xml_xpath_runner.html.ini +++ /dev/null @@ -1,3072 +0,0 @@ -[xml_xpath_runner.html] - [XPath tests] - expected: FAIL - - [XPath tests 1] - expected: FAIL - - [XPath tests 2] - expected: FAIL - - [XPath tests 3] - expected: FAIL - - [XPath tests 4] - expected: FAIL - - [XPath tests 5] - expected: FAIL - - [XPath tests 6] - expected: FAIL - - [XPath tests 7] - expected: FAIL - - [XPath tests 8] - expected: FAIL - - [XPath tests 9] - expected: FAIL - - [XPath tests 10] - expected: FAIL - - [XPath tests 11] - expected: FAIL - - [XPath tests 12] - expected: FAIL - - [XPath tests 13] - expected: FAIL - - [XPath tests 14] - expected: FAIL - - [XPath tests 15] - expected: FAIL - - [XPath tests 16] - expected: FAIL - - [XPath tests 17] - expected: FAIL - - [XPath tests 18] - expected: FAIL - - [XPath tests 19] - expected: FAIL - - [XPath tests 20] - expected: FAIL - - [XPath tests 21] - expected: FAIL - - [XPath tests 22] - expected: FAIL - - [XPath tests 23] - expected: FAIL - - [XPath tests 24] - expected: FAIL - - [XPath tests 25] - expected: FAIL - - [XPath tests 26] - expected: FAIL - - [XPath tests 27] - expected: FAIL - - [XPath tests 28] - expected: FAIL - - [XPath tests 29] - expected: FAIL - - [XPath tests 30] - expected: FAIL - - [XPath tests 31] - expected: FAIL - - [XPath tests 32] - expected: FAIL - - [XPath tests 33] - expected: FAIL - - [XPath tests 34] - expected: FAIL - - [XPath tests 35] - expected: FAIL - - [XPath tests 36] - expected: FAIL - - [XPath tests 37] - expected: FAIL - - [XPath tests 38] - expected: FAIL - - [XPath tests 39] - expected: FAIL - - [XPath tests 40] - expected: FAIL - - [XPath tests 41] - expected: FAIL - - [XPath tests 42] - expected: FAIL - - [XPath tests 43] - expected: FAIL - - [XPath tests 44] - expected: FAIL - - [XPath tests 45] - expected: FAIL - - [XPath tests 46] - expected: FAIL - - [XPath tests 47] - expected: FAIL - - [XPath tests 48] - expected: FAIL - - [XPath tests 49] - expected: FAIL - - [XPath tests 50] - expected: FAIL - - [XPath tests 51] - expected: FAIL - - [XPath tests 52] - expected: FAIL - - [XPath tests 53] - expected: FAIL - - [XPath tests 54] - expected: FAIL - - [XPath tests 55] - expected: FAIL - - [XPath tests 56] - expected: FAIL - - [XPath tests 57] - expected: FAIL - - [XPath tests 58] - expected: FAIL - - [XPath tests 59] - expected: FAIL - - [XPath tests 60] - expected: FAIL - - [XPath tests 61] - expected: FAIL - - [XPath tests 62] - expected: FAIL - - [XPath tests 63] - expected: FAIL - - [XPath tests 64] - expected: FAIL - - [XPath tests 65] - expected: FAIL - - [XPath tests 66] - expected: FAIL - - [XPath tests 67] - expected: FAIL - - [XPath tests 68] - expected: FAIL - - [XPath tests 69] - expected: FAIL - - [XPath tests 70] - expected: FAIL - - [XPath tests 71] - expected: FAIL - - [XPath tests 72] - expected: FAIL - - [XPath tests 73] - expected: FAIL - - [XPath tests 74] - expected: FAIL - - [XPath tests 75] - expected: FAIL - - [XPath tests 76] - expected: FAIL - - [XPath tests 77] - expected: FAIL - - [XPath tests 78] - expected: FAIL - - [XPath tests 79] - expected: FAIL - - [XPath tests 80] - expected: FAIL - - [XPath tests 81] - expected: FAIL - - [XPath tests 82] - expected: FAIL - - [XPath tests 83] - expected: FAIL - - [XPath tests 84] - expected: FAIL - - [XPath tests 85] - expected: FAIL - - [XPath tests 86] - expected: FAIL - - [XPath tests 87] - expected: FAIL - - [XPath tests 88] - expected: FAIL - - [XPath tests 89] - expected: FAIL - - [XPath tests 90] - expected: FAIL - - [XPath tests 91] - expected: FAIL - - [XPath tests 92] - expected: FAIL - - [XPath tests 93] - expected: FAIL - - [XPath tests 94] - expected: FAIL - - [XPath tests 95] - expected: FAIL - - [XPath tests 96] - expected: FAIL - - [XPath tests 97] - expected: FAIL - - [XPath tests 98] - expected: FAIL - - [XPath tests 99] - expected: FAIL - - [XPath tests 100] - expected: FAIL - - [XPath tests 101] - expected: FAIL - - [XPath tests 102] - expected: FAIL - - [XPath tests 103] - expected: FAIL - - [XPath tests 104] - expected: FAIL - - [XPath tests 105] - expected: FAIL - - [XPath tests 106] - expected: FAIL - - [XPath tests 107] - expected: FAIL - - [XPath tests 108] - expected: FAIL - - [XPath tests 109] - expected: FAIL - - [XPath tests 110] - expected: FAIL - - [XPath tests 111] - expected: FAIL - - [XPath tests 112] - expected: FAIL - - [XPath tests 113] - expected: FAIL - - [XPath tests 114] - expected: FAIL - - [XPath tests 115] - expected: FAIL - - [XPath tests 116] - expected: FAIL - - [XPath tests 117] - expected: FAIL - - [XPath tests 118] - expected: FAIL - - [XPath tests 119] - expected: FAIL - - [XPath tests 120] - expected: FAIL - - [XPath tests 121] - expected: FAIL - - [XPath tests 122] - expected: FAIL - - [XPath tests 123] - expected: FAIL - - [XPath tests 124] - expected: FAIL - - [XPath tests 125] - expected: FAIL - - [XPath tests 126] - expected: FAIL - - [XPath tests 127] - expected: FAIL - - [XPath tests 128] - expected: FAIL - - [XPath tests 129] - expected: FAIL - - [XPath tests 130] - expected: FAIL - - [XPath tests 131] - expected: FAIL - - [XPath tests 132] - expected: FAIL - - [XPath tests 133] - expected: FAIL - - [XPath tests 134] - expected: FAIL - - [XPath tests 135] - expected: FAIL - - [XPath tests 136] - expected: FAIL - - [XPath tests 137] - expected: FAIL - - [XPath tests 138] - expected: FAIL - - [XPath tests 139] - expected: FAIL - - [XPath tests 140] - expected: FAIL - - [XPath tests 141] - expected: FAIL - - [XPath tests 142] - expected: FAIL - - [XPath tests 143] - expected: FAIL - - [XPath tests 144] - expected: FAIL - - [XPath tests 145] - expected: FAIL - - [XPath tests 146] - expected: FAIL - - [XPath tests 147] - expected: FAIL - - [XPath tests 148] - expected: FAIL - - [XPath tests 149] - expected: FAIL - - [XPath tests 150] - expected: FAIL - - [XPath tests 151] - expected: FAIL - - [XPath tests 152] - expected: FAIL - - [XPath tests 153] - expected: FAIL - - [XPath tests 154] - expected: FAIL - - [XPath tests 155] - expected: FAIL - - [XPath tests 156] - expected: FAIL - - [XPath tests 157] - expected: FAIL - - [XPath tests 158] - expected: FAIL - - [XPath tests 159] - expected: FAIL - - [XPath tests 160] - expected: FAIL - - [XPath tests 161] - expected: FAIL - - [XPath tests 162] - expected: FAIL - - [XPath tests 163] - expected: FAIL - - [XPath tests 164] - expected: FAIL - - [XPath tests 165] - expected: FAIL - - [XPath tests 166] - expected: FAIL - - [XPath tests 167] - expected: FAIL - - [XPath tests 168] - expected: FAIL - - [XPath tests 169] - expected: FAIL - - [XPath tests 170] - expected: FAIL - - [XPath tests 171] - expected: FAIL - - [XPath tests 172] - expected: FAIL - - [XPath tests 173] - expected: FAIL - - [XPath tests 174] - expected: FAIL - - [XPath tests 175] - expected: FAIL - - [XPath tests 176] - expected: FAIL - - [XPath tests 177] - expected: FAIL - - [XPath tests 178] - expected: FAIL - - [XPath tests 179] - expected: FAIL - - [XPath tests 180] - expected: FAIL - - [XPath tests 181] - expected: FAIL - - [XPath tests 182] - expected: FAIL - - [XPath tests 183] - expected: FAIL - - [XPath tests 184] - expected: FAIL - - [XPath tests 185] - expected: FAIL - - [XPath tests 186] - expected: FAIL - - [XPath tests 187] - expected: FAIL - - [XPath tests 188] - expected: FAIL - - [XPath tests 189] - expected: FAIL - - [XPath tests 190] - expected: FAIL - - [XPath tests 191] - expected: FAIL - - [XPath tests 192] - expected: FAIL - - [XPath tests 193] - expected: FAIL - - [XPath tests 194] - expected: FAIL - - [XPath tests 195] - expected: FAIL - - [XPath tests 196] - expected: FAIL - - [XPath tests 197] - expected: FAIL - - [XPath tests 198] - expected: FAIL - - [XPath tests 199] - expected: FAIL - - [XPath tests 200] - expected: FAIL - - [XPath tests 201] - expected: FAIL - - [XPath tests 202] - expected: FAIL - - [XPath tests 203] - expected: FAIL - - [XPath tests 204] - expected: FAIL - - [XPath tests 205] - expected: FAIL - - [XPath tests 206] - expected: FAIL - - [XPath tests 207] - expected: FAIL - - [XPath tests 208] - expected: FAIL - - [XPath tests 209] - expected: FAIL - - [XPath tests 210] - expected: FAIL - - [XPath tests 211] - expected: FAIL - - [XPath tests 212] - expected: FAIL - - [XPath tests 213] - expected: FAIL - - [XPath tests 214] - expected: FAIL - - [XPath tests 215] - expected: FAIL - - [XPath tests 216] - expected: FAIL - - [XPath tests 217] - expected: FAIL - - [XPath tests 218] - expected: FAIL - - [XPath tests 219] - expected: FAIL - - [XPath tests 220] - expected: FAIL - - [XPath tests 221] - expected: FAIL - - [XPath tests 222] - expected: FAIL - - [XPath tests 223] - expected: FAIL - - [XPath tests 224] - expected: FAIL - - [XPath tests 225] - expected: FAIL - - [XPath tests 226] - expected: FAIL - - [XPath tests 227] - expected: FAIL - - [XPath tests 228] - expected: FAIL - - [XPath tests 229] - expected: FAIL - - [XPath tests 230] - expected: FAIL - - [XPath tests 231] - expected: FAIL - - [XPath tests 232] - expected: FAIL - - [XPath tests 233] - expected: FAIL - - [XPath tests 234] - expected: FAIL - - [XPath tests 235] - expected: FAIL - - [XPath tests 236] - expected: FAIL - - [XPath tests 237] - expected: FAIL - - [XPath tests 238] - expected: FAIL - - [XPath tests 239] - expected: FAIL - - [XPath tests 240] - expected: FAIL - - [XPath tests 241] - expected: FAIL - - [XPath tests 242] - expected: FAIL - - [XPath tests 243] - expected: FAIL - - [XPath tests 244] - expected: FAIL - - [XPath tests 245] - expected: FAIL - - [XPath tests 246] - expected: FAIL - - [XPath tests 247] - expected: FAIL - - [XPath tests 248] - expected: FAIL - - [XPath tests 249] - expected: FAIL - - [XPath tests 250] - expected: FAIL - - [XPath tests 251] - expected: FAIL - - [XPath tests 252] - expected: FAIL - - [XPath tests 253] - expected: FAIL - - [XPath tests 254] - expected: FAIL - - [XPath tests 255] - expected: FAIL - - [XPath tests 256] - expected: FAIL - - [XPath tests 257] - expected: FAIL - - [XPath tests 258] - expected: FAIL - - [XPath tests 259] - expected: FAIL - - [XPath tests 260] - expected: FAIL - - [XPath tests 261] - expected: FAIL - - [XPath tests 262] - expected: FAIL - - [XPath tests 263] - expected: FAIL - - [XPath tests 264] - expected: FAIL - - [XPath tests 265] - expected: FAIL - - [XPath tests 266] - expected: FAIL - - [XPath tests 267] - expected: FAIL - - [XPath tests 268] - expected: FAIL - - [XPath tests 269] - expected: FAIL - - [XPath tests 270] - expected: FAIL - - [XPath tests 271] - expected: FAIL - - [XPath tests 272] - expected: FAIL - - [XPath tests 273] - expected: FAIL - - [XPath tests 274] - expected: FAIL - - [XPath tests 275] - expected: FAIL - - [XPath tests 276] - expected: FAIL - - [XPath tests 277] - expected: FAIL - - [XPath tests 278] - expected: FAIL - - [XPath tests 279] - expected: FAIL - - [XPath tests 280] - expected: FAIL - - [XPath tests 281] - expected: FAIL - - [XPath tests 282] - expected: FAIL - - [XPath tests 283] - expected: FAIL - - [XPath tests 284] - expected: FAIL - - [XPath tests 285] - expected: FAIL - - [XPath tests 286] - expected: FAIL - - [XPath tests 287] - expected: FAIL - - [XPath tests 288] - expected: FAIL - - [XPath tests 289] - expected: FAIL - - [XPath tests 290] - expected: FAIL - - [XPath tests 291] - expected: FAIL - - [XPath tests 292] - expected: FAIL - - [XPath tests 293] - expected: FAIL - - [XPath tests 294] - expected: FAIL - - [XPath tests 295] - expected: FAIL - - [XPath tests 296] - expected: FAIL - - [XPath tests 297] - expected: FAIL - - [XPath tests 298] - expected: FAIL - - [XPath tests 299] - expected: FAIL - - [XPath tests 300] - expected: FAIL - - [XPath tests 301] - expected: FAIL - - [XPath tests 302] - expected: FAIL - - [XPath tests 303] - expected: FAIL - - [XPath tests 304] - expected: FAIL - - [XPath tests 305] - expected: FAIL - - [XPath tests 306] - expected: FAIL - - [XPath tests 307] - expected: FAIL - - [XPath tests 308] - expected: FAIL - - [XPath tests 309] - expected: FAIL - - [XPath tests 310] - expected: FAIL - - [XPath tests 311] - expected: FAIL - - [XPath tests 312] - expected: FAIL - - [XPath tests 313] - expected: FAIL - - [XPath tests 314] - expected: FAIL - - [XPath tests 315] - expected: FAIL - - [XPath tests 316] - expected: FAIL - - [XPath tests 317] - expected: FAIL - - [XPath tests 318] - expected: FAIL - - [XPath tests 319] - expected: FAIL - - [XPath tests 320] - expected: FAIL - - [XPath tests 321] - expected: FAIL - - [XPath tests 322] - expected: FAIL - - [XPath tests 323] - expected: FAIL - - [XPath tests 324] - expected: FAIL - - [XPath tests 325] - expected: FAIL - - [XPath tests 326] - expected: FAIL - - [XPath tests 327] - expected: FAIL - - [XPath tests 328] - expected: FAIL - - [XPath tests 329] - expected: FAIL - - [XPath tests 330] - expected: FAIL - - [XPath tests 331] - expected: FAIL - - [XPath tests 332] - expected: FAIL - - [XPath tests 333] - expected: FAIL - - [XPath tests 334] - expected: FAIL - - [XPath tests 335] - expected: FAIL - - [XPath tests 336] - expected: FAIL - - [XPath tests 337] - expected: FAIL - - [XPath tests 338] - expected: FAIL - - [XPath tests 339] - expected: FAIL - - [XPath tests 340] - expected: FAIL - - [XPath tests 341] - expected: FAIL - - [XPath tests 342] - expected: FAIL - - [XPath tests 343] - expected: FAIL - - [XPath tests 344] - expected: FAIL - - [XPath tests 345] - expected: FAIL - - [XPath tests 346] - expected: FAIL - - [XPath tests 347] - expected: FAIL - - [XPath tests 348] - expected: FAIL - - [XPath tests 349] - expected: FAIL - - [XPath tests 350] - expected: FAIL - - [XPath tests 351] - expected: FAIL - - [XPath tests 352] - expected: FAIL - - [XPath tests 353] - expected: FAIL - - [XPath tests 354] - expected: FAIL - - [XPath tests 355] - expected: FAIL - - [XPath tests 356] - expected: FAIL - - [XPath tests 357] - expected: FAIL - - [XPath tests 358] - expected: FAIL - - [XPath tests 359] - expected: FAIL - - [XPath tests 360] - expected: FAIL - - [XPath tests 361] - expected: FAIL - - [XPath tests 362] - expected: FAIL - - [XPath tests 363] - expected: FAIL - - [XPath tests 364] - expected: FAIL - - [XPath tests 365] - expected: FAIL - - [XPath tests 366] - expected: FAIL - - [XPath tests 367] - expected: FAIL - - [XPath tests 368] - expected: FAIL - - [XPath tests 369] - expected: FAIL - - [XPath tests 370] - expected: FAIL - - [XPath tests 371] - expected: FAIL - - [XPath tests 372] - expected: FAIL - - [XPath tests 373] - expected: FAIL - - [XPath tests 374] - expected: FAIL - - [XPath tests 375] - expected: FAIL - - [XPath tests 376] - expected: FAIL - - [XPath tests 377] - expected: FAIL - - [XPath tests 378] - expected: FAIL - - [XPath tests 379] - expected: FAIL - - [XPath tests 380] - expected: FAIL - - [XPath tests 381] - expected: FAIL - - [XPath tests 382] - expected: FAIL - - [XPath tests 383] - expected: FAIL - - [XPath tests 384] - expected: FAIL - - [XPath tests 385] - expected: FAIL - - [XPath tests 386] - expected: FAIL - - [XPath tests 387] - expected: FAIL - - [XPath tests 388] - expected: FAIL - - [XPath tests 389] - expected: FAIL - - [XPath tests 390] - expected: FAIL - - [XPath tests 391] - expected: FAIL - - [XPath tests 392] - expected: FAIL - - [XPath tests 393] - expected: FAIL - - [XPath tests 394] - expected: FAIL - - [XPath tests 395] - expected: FAIL - - [XPath tests 396] - expected: FAIL - - [XPath tests 397] - expected: FAIL - - [XPath tests 398] - expected: FAIL - - [XPath tests 399] - expected: FAIL - - [XPath tests 400] - expected: FAIL - - [XPath tests 401] - expected: FAIL - - [XPath tests 402] - expected: FAIL - - [XPath tests 403] - expected: FAIL - - [XPath tests 404] - expected: FAIL - - [XPath tests 405] - expected: FAIL - - [XPath tests 406] - expected: FAIL - - [XPath tests 407] - expected: FAIL - - [XPath tests 408] - expected: FAIL - - [XPath tests 409] - expected: FAIL - - [XPath tests 410] - expected: FAIL - - [XPath tests 411] - expected: FAIL - - [XPath tests 412] - expected: FAIL - - [XPath tests 413] - expected: FAIL - - [XPath tests 414] - expected: FAIL - - [XPath tests 415] - expected: FAIL - - [XPath tests 416] - expected: FAIL - - [XPath tests 417] - expected: FAIL - - [XPath tests 418] - expected: FAIL - - [XPath tests 419] - expected: FAIL - - [XPath tests 420] - expected: FAIL - - [XPath tests 421] - expected: FAIL - - [XPath tests 422] - expected: FAIL - - [XPath tests 423] - expected: FAIL - - [XPath tests 424] - expected: FAIL - - [XPath tests 425] - expected: FAIL - - [XPath tests 426] - expected: FAIL - - [XPath tests 427] - expected: FAIL - - [XPath tests 428] - expected: FAIL - - [XPath tests 429] - expected: FAIL - - [XPath tests 430] - expected: FAIL - - [XPath tests 431] - expected: FAIL - - [XPath tests 432] - expected: FAIL - - [XPath tests 433] - expected: FAIL - - [XPath tests 434] - expected: FAIL - - [XPath tests 435] - expected: FAIL - - [XPath tests 436] - expected: FAIL - - [XPath tests 437] - expected: FAIL - - [XPath tests 438] - expected: FAIL - - [XPath tests 439] - expected: FAIL - - [XPath tests 440] - expected: FAIL - - [XPath tests 441] - expected: FAIL - - [XPath tests 442] - expected: FAIL - - [XPath tests 443] - expected: FAIL - - [XPath tests 444] - expected: FAIL - - [XPath tests 445] - expected: FAIL - - [XPath tests 446] - expected: FAIL - - [XPath tests 447] - expected: FAIL - - [XPath tests 448] - expected: FAIL - - [XPath tests 449] - expected: FAIL - - [XPath tests 450] - expected: FAIL - - [XPath tests 451] - expected: FAIL - - [XPath tests 452] - expected: FAIL - - [XPath tests 453] - expected: FAIL - - [XPath tests 454] - expected: FAIL - - [XPath tests 455] - expected: FAIL - - [XPath tests 456] - expected: FAIL - - [XPath tests 457] - expected: FAIL - - [XPath tests 458] - expected: FAIL - - [XPath tests 459] - expected: FAIL - - [XPath tests 460] - expected: FAIL - - [XPath tests 461] - expected: FAIL - - [XPath tests 462] - expected: FAIL - - [XPath tests 463] - expected: FAIL - - [XPath tests 464] - expected: FAIL - - [XPath tests 465] - expected: FAIL - - [XPath tests 466] - expected: FAIL - - [XPath tests 467] - expected: FAIL - - [XPath tests 468] - expected: FAIL - - [XPath tests 469] - expected: FAIL - - [XPath tests 470] - expected: FAIL - - [XPath tests 471] - expected: FAIL - - [XPath tests 472] - expected: FAIL - - [XPath tests 473] - expected: FAIL - - [XPath tests 474] - expected: FAIL - - [XPath tests 475] - expected: FAIL - - [XPath tests 476] - expected: FAIL - - [XPath tests 477] - expected: FAIL - - [XPath tests 478] - expected: FAIL - - [XPath tests 479] - expected: FAIL - - [XPath tests 480] - expected: FAIL - - [XPath tests 481] - expected: FAIL - - [XPath tests 482] - expected: FAIL - - [XPath tests 483] - expected: FAIL - - [XPath tests 484] - expected: FAIL - - [XPath tests 485] - expected: FAIL - - [XPath tests 486] - expected: FAIL - - [XPath tests 487] - expected: FAIL - - [XPath tests 488] - expected: FAIL - - [XPath tests 489] - expected: FAIL - - [XPath tests 490] - expected: FAIL - - [XPath tests 491] - expected: FAIL - - [XPath tests 492] - expected: FAIL - - [XPath tests 493] - expected: FAIL - - [XPath tests 494] - expected: FAIL - - [XPath tests 495] - expected: FAIL - - [XPath tests 496] - expected: FAIL - - [XPath tests 497] - expected: FAIL - - [XPath tests 498] - expected: FAIL - - [XPath tests 499] - expected: FAIL - - [XPath tests 500] - expected: FAIL - - [XPath tests 501] - expected: FAIL - - [XPath tests 502] - expected: FAIL - - [XPath tests 503] - expected: FAIL - - [XPath tests 504] - expected: FAIL - - [XPath tests 505] - expected: FAIL - - [XPath tests 506] - expected: FAIL - - [XPath tests 507] - expected: FAIL - - [XPath tests 508] - expected: FAIL - - [XPath tests 509] - expected: FAIL - - [XPath tests 510] - expected: FAIL - - [XPath tests 511] - expected: FAIL - - [XPath tests 512] - expected: FAIL - - [XPath tests 513] - expected: FAIL - - [XPath tests 514] - expected: FAIL - - [XPath tests 515] - expected: FAIL - - [XPath tests 516] - expected: FAIL - - [XPath tests 517] - expected: FAIL - - [XPath tests 518] - expected: FAIL - - [XPath tests 519] - expected: FAIL - - [XPath tests 520] - expected: FAIL - - [XPath tests 521] - expected: FAIL - - [XPath tests 522] - expected: FAIL - - [XPath tests 523] - expected: FAIL - - [XPath tests 524] - expected: FAIL - - [XPath tests 525] - expected: FAIL - - [XPath tests 526] - expected: FAIL - - [XPath tests 527] - expected: FAIL - - [XPath tests 528] - expected: FAIL - - [XPath tests 529] - expected: FAIL - - [XPath tests 530] - expected: FAIL - - [XPath tests 531] - expected: FAIL - - [XPath tests 532] - expected: FAIL - - [XPath tests 533] - expected: FAIL - - [XPath tests 534] - expected: FAIL - - [XPath tests 535] - expected: FAIL - - [XPath tests 536] - expected: FAIL - - [XPath tests 537] - expected: FAIL - - [XPath tests 538] - expected: FAIL - - [XPath tests 539] - expected: FAIL - - [XPath tests 540] - expected: FAIL - - [XPath tests 541] - expected: FAIL - - [XPath tests 542] - expected: FAIL - - [XPath tests 543] - expected: FAIL - - [XPath tests 544] - expected: FAIL - - [XPath tests 545] - expected: FAIL - - [XPath tests 546] - expected: FAIL - - [XPath tests 547] - expected: FAIL - - [XPath tests 548] - expected: FAIL - - [XPath tests 549] - expected: FAIL - - [XPath tests 550] - expected: FAIL - - [XPath tests 551] - expected: FAIL - - [XPath tests 552] - expected: FAIL - - [XPath tests 553] - expected: FAIL - - [XPath tests 554] - expected: FAIL - - [XPath tests 555] - expected: FAIL - - [XPath tests 556] - expected: FAIL - - [XPath tests 557] - expected: FAIL - - [XPath tests 558] - expected: FAIL - - [XPath tests 559] - expected: FAIL - - [XPath tests 560] - expected: FAIL - - [XPath tests 561] - expected: FAIL - - [XPath tests 562] - expected: FAIL - - [XPath tests 563] - expected: FAIL - - [XPath tests 564] - expected: FAIL - - [XPath tests 565] - expected: FAIL - - [XPath tests 566] - expected: FAIL - - [XPath tests 567] - expected: FAIL - - [XPath tests 568] - expected: FAIL - - [XPath tests 569] - expected: FAIL - - [XPath tests 570] - expected: FAIL - - [XPath tests 571] - expected: FAIL - - [XPath tests 572] - expected: FAIL - - [XPath tests 573] - expected: FAIL - - [XPath tests 574] - expected: FAIL - - [XPath tests 575] - expected: FAIL - - [XPath tests 576] - expected: FAIL - - [XPath tests 577] - expected: FAIL - - [XPath tests 578] - expected: FAIL - - [XPath tests 579] - expected: FAIL - - [XPath tests 580] - expected: FAIL - - [XPath tests 581] - expected: FAIL - - [XPath tests 582] - expected: FAIL - - [XPath tests 583] - expected: FAIL - - [XPath tests 584] - expected: FAIL - - [XPath tests 585] - expected: FAIL - - [XPath tests 586] - expected: FAIL - - [XPath tests 587] - expected: FAIL - - [XPath tests 588] - expected: FAIL - - [XPath tests 589] - expected: FAIL - - [XPath tests 590] - expected: FAIL - - [XPath tests 591] - expected: FAIL - - [XPath tests 592] - expected: FAIL - - [XPath tests 593] - expected: FAIL - - [XPath tests 594] - expected: FAIL - - [XPath tests 595] - expected: FAIL - - [XPath tests 596] - expected: FAIL - - [XPath tests 597] - expected: FAIL - - [XPath tests 598] - expected: FAIL - - [XPath tests 599] - expected: FAIL - - [XPath tests 600] - expected: FAIL - - [XPath tests 601] - expected: FAIL - - [XPath tests 602] - expected: FAIL - - [XPath tests 603] - expected: FAIL - - [XPath tests 604] - expected: FAIL - - [XPath tests 605] - expected: FAIL - - [XPath tests 606] - expected: FAIL - - [XPath tests 607] - expected: FAIL - - [XPath tests 608] - expected: FAIL - - [XPath tests 609] - expected: FAIL - - [XPath tests 610] - expected: FAIL - - [XPath tests 611] - expected: FAIL - - [XPath tests 612] - expected: FAIL - - [XPath tests 613] - expected: FAIL - - [XPath tests 614] - expected: FAIL - - [XPath tests 615] - expected: FAIL - - [XPath tests 616] - expected: FAIL - - [XPath tests 617] - expected: FAIL - - [XPath tests 618] - expected: FAIL - - [XPath tests 619] - expected: FAIL - - [XPath tests 620] - expected: FAIL - - [XPath tests 621] - expected: FAIL - - [XPath tests 622] - expected: FAIL - - [XPath tests 623] - expected: FAIL - - [XPath tests 624] - expected: FAIL - - [XPath tests 625] - expected: FAIL - - [XPath tests 626] - expected: FAIL - - [XPath tests 627] - expected: FAIL - - [XPath tests 628] - expected: FAIL - - [XPath tests 629] - expected: FAIL - - [XPath tests 630] - expected: FAIL - - [XPath tests 631] - expected: FAIL - - [XPath tests 632] - expected: FAIL - - [XPath tests 633] - expected: FAIL - - [XPath tests 634] - expected: FAIL - - [XPath tests 635] - expected: FAIL - - [XPath tests 636] - expected: FAIL - - [XPath tests 637] - expected: FAIL - - [XPath tests 638] - expected: FAIL - - [XPath tests 639] - expected: FAIL - - [XPath tests 640] - expected: FAIL - - [XPath tests 641] - expected: FAIL - - [XPath tests 642] - expected: FAIL - - [XPath tests 643] - expected: FAIL - - [XPath tests 644] - expected: FAIL - - [XPath tests 645] - expected: FAIL - - [XPath tests 646] - expected: FAIL - - [XPath tests 647] - expected: FAIL - - [XPath tests 648] - expected: FAIL - - [XPath tests 649] - expected: FAIL - - [XPath tests 650] - expected: FAIL - - [XPath tests 651] - expected: FAIL - - [XPath tests 652] - expected: FAIL - - [XPath tests 653] - expected: FAIL - - [XPath tests 654] - expected: FAIL - - [XPath tests 655] - expected: FAIL - - [XPath tests 656] - expected: FAIL - - [XPath tests 657] - expected: FAIL - - [XPath tests 658] - expected: FAIL - - [XPath tests 659] - expected: FAIL - - [XPath tests 660] - expected: FAIL - - [XPath tests 661] - expected: FAIL - - [XPath tests 662] - expected: FAIL - - [XPath tests 663] - expected: FAIL - - [XPath tests 664] - expected: FAIL - - [XPath tests 665] - expected: FAIL - - [XPath tests 666] - expected: FAIL - - [XPath tests 667] - expected: FAIL - - [XPath tests 668] - expected: FAIL - - [XPath tests 669] - expected: FAIL - - [XPath tests 670] - expected: FAIL - - [XPath tests 671] - expected: FAIL - - [XPath tests 672] - expected: FAIL - - [XPath tests 673] - expected: FAIL - - [XPath tests 674] - expected: FAIL - - [XPath tests 675] - expected: FAIL - - [XPath tests 676] - expected: FAIL - - [XPath tests 677] - expected: FAIL - - [XPath tests 678] - expected: FAIL - - [XPath tests 679] - expected: FAIL - - [XPath tests 680] - expected: FAIL - - [XPath tests 681] - expected: FAIL - - [XPath tests 682] - expected: FAIL - - [XPath tests 683] - expected: FAIL - - [XPath tests 684] - expected: FAIL - - [XPath tests 685] - expected: FAIL - - [XPath tests 686] - expected: FAIL - - [XPath tests 687] - expected: FAIL - - [XPath tests 688] - expected: FAIL - - [XPath tests 689] - expected: FAIL - - [XPath tests 690] - expected: FAIL - - [XPath tests 691] - expected: FAIL - - [XPath tests 692] - expected: FAIL - - [XPath tests 693] - expected: FAIL - - [XPath tests 694] - expected: FAIL - - [XPath tests 695] - expected: FAIL - - [XPath tests 696] - expected: FAIL - - [XPath tests 697] - expected: FAIL - - [XPath tests 698] - expected: FAIL - - [XPath tests 699] - expected: FAIL - - [XPath tests 700] - expected: FAIL - - [XPath tests 701] - expected: FAIL - - [XPath tests 702] - expected: FAIL - - [XPath tests 703] - expected: FAIL - - [XPath tests 704] - expected: FAIL - - [XPath tests 705] - expected: FAIL - - [XPath tests 706] - expected: FAIL - - [XPath tests 707] - expected: FAIL - - [XPath tests 708] - expected: FAIL - - [XPath tests 709] - expected: FAIL - - [XPath tests 710] - expected: FAIL - - [XPath tests 711] - expected: FAIL - - [XPath tests 712] - expected: FAIL - - [XPath tests 713] - expected: FAIL - - [XPath tests 714] - expected: FAIL - - [XPath tests 715] - expected: FAIL - - [XPath tests 716] - expected: FAIL - - [XPath tests 717] - expected: FAIL - - [XPath tests 718] - expected: FAIL - - [XPath tests 719] - expected: FAIL - - [XPath tests 720] - expected: FAIL - - [XPath tests 721] - expected: FAIL - - [XPath tests 722] - expected: FAIL - - [XPath tests 723] - expected: FAIL - - [XPath tests 724] - expected: FAIL - - [XPath tests 725] - expected: FAIL - - [XPath tests 726] - expected: FAIL - - [XPath tests 727] - expected: FAIL - - [XPath tests 728] - expected: FAIL - - [XPath tests 729] - expected: FAIL - - [XPath tests 730] - expected: FAIL - - [XPath tests 731] - expected: FAIL - - [XPath tests 732] - expected: FAIL - - [XPath tests 733] - expected: FAIL - - [XPath tests 734] - expected: FAIL - - [XPath tests 735] - expected: FAIL - - [XPath tests 736] - expected: FAIL - - [XPath tests 737] - expected: FAIL - - [XPath tests 738] - expected: FAIL - - [XPath tests 739] - expected: FAIL - - [XPath tests 740] - expected: FAIL - - [XPath tests 741] - expected: FAIL - - [XPath tests 742] - expected: FAIL - - [XPath tests 743] - expected: FAIL - - [XPath tests 744] - expected: FAIL - - [XPath tests 745] - expected: FAIL - - [XPath tests 746] - expected: FAIL - - [XPath tests 747] - expected: FAIL - - [XPath tests 748] - expected: FAIL - - [XPath tests 749] - expected: FAIL - - [XPath tests 750] - expected: FAIL - - [XPath tests 751] - expected: FAIL - - [XPath tests 752] - expected: FAIL - - [XPath tests 753] - expected: FAIL - - [XPath tests 754] - expected: FAIL - - [XPath tests 755] - expected: FAIL - - [XPath tests 756] - expected: FAIL - - [XPath tests 757] - expected: FAIL - - [XPath tests 758] - expected: FAIL - - [XPath tests 759] - expected: FAIL - - [XPath tests 760] - expected: FAIL - - [XPath tests 761] - expected: FAIL - - [XPath tests 762] - expected: FAIL - - [XPath tests 763] - expected: FAIL - - [XPath tests 764] - expected: FAIL - - [XPath tests 765] - expected: FAIL - - [XPath tests 766] - expected: FAIL - - [XPath tests 767] - expected: FAIL - - [XPath tests 768] - expected: FAIL - - [XPath tests 769] - expected: FAIL - - [XPath tests 770] - expected: FAIL - - [XPath tests 771] - expected: FAIL - - [XPath tests 772] - expected: FAIL - - [XPath tests 773] - expected: FAIL - - [XPath tests 774] - expected: FAIL - - [XPath tests 775] - expected: FAIL - - [XPath tests 776] - expected: FAIL - - [XPath tests 777] - expected: FAIL - - [XPath tests 778] - expected: FAIL - - [XPath tests 779] - expected: FAIL - - [XPath tests 780] - expected: FAIL - - [XPath tests 781] - expected: FAIL - - [XPath tests 782] - expected: FAIL - - [XPath tests 783] - expected: FAIL - - [XPath tests 784] - expected: FAIL - - [XPath tests 785] - expected: FAIL - - [XPath tests 786] - expected: FAIL - - [XPath tests 787] - expected: FAIL - - [XPath tests 788] - expected: FAIL - - [XPath tests 789] - expected: FAIL - - [XPath tests 790] - expected: FAIL - - [XPath tests 791] - expected: FAIL - - [XPath tests 792] - expected: FAIL - - [XPath tests 793] - expected: FAIL - - [XPath tests 794] - expected: FAIL - - [XPath tests 795] - expected: FAIL - - [XPath tests 796] - expected: FAIL - - [XPath tests 797] - expected: FAIL - - [XPath tests 798] - expected: FAIL - - [XPath tests 799] - expected: FAIL - - [XPath tests 800] - expected: FAIL - - [XPath tests 801] - expected: FAIL - - [XPath tests 802] - expected: FAIL - - [XPath tests 803] - expected: FAIL - - [XPath tests 804] - expected: FAIL - - [XPath tests 805] - expected: FAIL - - [XPath tests 806] - expected: FAIL - - [XPath tests 807] - expected: FAIL - - [XPath tests 808] - expected: FAIL - - [XPath tests 809] - expected: FAIL - - [XPath tests 810] - expected: FAIL - - [XPath tests 811] - expected: FAIL - - [XPath tests 812] - expected: FAIL - - [XPath tests 813] - expected: FAIL - - [XPath tests 814] - expected: FAIL - - [XPath tests 815] - expected: FAIL - - [XPath tests 816] - expected: FAIL - - [XPath tests 817] - expected: FAIL - - [XPath tests 818] - expected: FAIL - - [XPath tests 819] - expected: FAIL - - [XPath tests 820] - expected: FAIL - - [XPath tests 821] - expected: FAIL - - [XPath tests 822] - expected: FAIL - - [XPath tests 823] - expected: FAIL - - [XPath tests 824] - expected: FAIL - - [XPath tests 825] - expected: FAIL - - [XPath tests 826] - expected: FAIL - - [XPath tests 827] - expected: FAIL - - [XPath tests 828] - expected: FAIL - - [XPath tests 829] - expected: FAIL - - [XPath tests 830] - expected: FAIL - - [XPath tests 831] - expected: FAIL - - [XPath tests 832] - expected: FAIL - - [XPath tests 833] - expected: FAIL - - [XPath tests 834] - expected: FAIL - - [XPath tests 835] - expected: FAIL - - [XPath tests 836] - expected: FAIL - - [XPath tests 837] - expected: FAIL - - [XPath tests 838] - expected: FAIL - - [XPath tests 839] - expected: FAIL - - [XPath tests 840] - expected: FAIL - - [XPath tests 841] - expected: FAIL - - [XPath tests 842] - expected: FAIL - - [XPath tests 843] - expected: FAIL - - [XPath tests 844] - expected: FAIL - - [XPath tests 845] - expected: FAIL - - [XPath tests 846] - expected: FAIL - - [XPath tests 847] - expected: FAIL - - [XPath tests 848] - expected: FAIL - - [XPath tests 849] - expected: FAIL - - [XPath tests 850] - expected: FAIL - - [XPath tests 851] - expected: FAIL - - [XPath tests 852] - expected: FAIL - - [XPath tests 853] - expected: FAIL - - [XPath tests 854] - expected: FAIL - - [XPath tests 855] - expected: FAIL - - [XPath tests 856] - expected: FAIL - - [XPath tests 857] - expected: FAIL - - [XPath tests 858] - expected: FAIL - - [XPath tests 859] - expected: FAIL - - [XPath tests 860] - expected: FAIL - - [XPath tests 861] - expected: FAIL - - [XPath tests 862] - expected: FAIL - - [XPath tests 863] - expected: FAIL - - [XPath tests 864] - expected: FAIL - - [XPath tests 865] - expected: FAIL - - [XPath tests 866] - expected: FAIL - - [XPath tests 867] - expected: FAIL - - [XPath tests 868] - expected: FAIL - - [XPath tests 869] - expected: FAIL - - [XPath tests 870] - expected: FAIL - - [XPath tests 871] - expected: FAIL - - [XPath tests 872] - expected: FAIL - - [XPath tests 873] - expected: FAIL - - [XPath tests 874] - expected: FAIL - - [XPath tests 875] - expected: FAIL - - [XPath tests 876] - expected: FAIL - - [XPath tests 877] - expected: FAIL - - [XPath tests 878] - expected: FAIL - - [XPath tests 879] - expected: FAIL - - [XPath tests 880] - expected: FAIL - - [XPath tests 881] - expected: FAIL - - [XPath tests 882] - expected: FAIL - - [XPath tests 883] - expected: FAIL - - [XPath tests 884] - expected: FAIL - - [XPath tests 885] - expected: FAIL - - [XPath tests 886] - expected: FAIL - - [XPath tests 887] - expected: FAIL - - [XPath tests 888] - expected: FAIL - - [XPath tests 889] - expected: FAIL - - [XPath tests 890] - expected: FAIL - - [XPath tests 891] - expected: FAIL - - [XPath tests 892] - expected: FAIL - - [XPath tests 893] - expected: FAIL - - [XPath tests 894] - expected: FAIL - - [XPath tests 895] - expected: FAIL - - [XPath tests 896] - expected: FAIL - - [XPath tests 897] - expected: FAIL - - [XPath tests 898] - expected: FAIL - - [XPath tests 899] - expected: FAIL - - [XPath tests 900] - expected: FAIL - - [XPath tests 901] - expected: FAIL - - [XPath tests 902] - expected: FAIL - - [XPath tests 903] - expected: FAIL - - [XPath tests 904] - expected: FAIL - - [XPath tests 905] - expected: FAIL - - [XPath tests 906] - expected: FAIL - - [XPath tests 907] - expected: FAIL - - [XPath tests 908] - expected: FAIL - - [XPath tests 909] - expected: FAIL - - [XPath tests 910] - expected: FAIL - - [XPath tests 911] - expected: FAIL - - [XPath tests 912] - expected: FAIL - - [XPath tests 913] - expected: FAIL - - [XPath tests 914] - expected: FAIL - - [XPath tests 915] - expected: FAIL - - [XPath tests 916] - expected: FAIL - - [XPath tests 917] - expected: FAIL - - [XPath tests 918] - expected: FAIL - - [XPath tests 919] - expected: FAIL - - [XPath tests 920] - expected: FAIL - - [XPath tests 921] - expected: FAIL - - [XPath tests 922] - expected: FAIL - - [XPath tests 923] - expected: FAIL - - [XPath tests 924] - expected: FAIL - - [XPath tests 925] - expected: FAIL - - [XPath tests 926] - expected: FAIL - - [XPath tests 927] - expected: FAIL - - [XPath tests 928] - expected: FAIL - - [XPath tests 929] - expected: FAIL - - [XPath tests 930] - expected: FAIL - - [XPath tests 931] - expected: FAIL - - [XPath tests 932] - expected: FAIL - - [XPath tests 933] - expected: FAIL - - [XPath tests 934] - expected: FAIL - - [XPath tests 935] - expected: FAIL - - [XPath tests 936] - expected: FAIL - - [XPath tests 937] - expected: FAIL - - [XPath tests 938] - expected: FAIL - - [XPath tests 939] - expected: FAIL - - [XPath tests 940] - expected: FAIL - - [XPath tests 941] - expected: FAIL - - [XPath tests 942] - expected: FAIL - - [XPath tests 943] - expected: FAIL - - [XPath tests 944] - expected: FAIL - - [XPath tests 945] - expected: FAIL - - [XPath tests 946] - expected: FAIL - - [XPath tests 947] - expected: FAIL - - [XPath tests 948] - expected: FAIL - - [XPath tests 949] - expected: FAIL - - [XPath tests 950] - expected: FAIL - - [XPath tests 951] - expected: FAIL - - [XPath tests 952] - expected: FAIL - - [XPath tests 953] - expected: FAIL - - [XPath tests 954] - expected: FAIL - - [XPath tests 955] - expected: FAIL - - [XPath tests 956] - expected: FAIL - - [XPath tests 957] - expected: FAIL - - [XPath tests 958] - expected: FAIL - - [XPath tests 959] - expected: FAIL - - [XPath tests 960] - expected: FAIL - - [XPath tests 961] - expected: FAIL - - [XPath tests 962] - expected: FAIL - - [XPath tests 963] - expected: FAIL - - [XPath tests 964] - expected: FAIL - - [XPath tests 965] - expected: FAIL - - [XPath tests 966] - expected: FAIL - - [XPath tests 967] - expected: FAIL - - [XPath tests 968] - expected: FAIL - - [XPath tests 969] - expected: FAIL - - [XPath tests 970] - expected: FAIL - - [XPath tests 971] - expected: FAIL - - [XPath tests 972] - expected: FAIL - - [XPath tests 973] - expected: FAIL - - [XPath tests 974] - expected: FAIL - - [XPath tests 975] - expected: FAIL - - [XPath tests 976] - expected: FAIL - - [XPath tests 977] - expected: FAIL - - [XPath tests 978] - expected: FAIL - - [XPath tests 979] - expected: FAIL - - [XPath tests 980] - expected: FAIL - - [XPath tests 981] - expected: FAIL - - [XPath tests 982] - expected: FAIL - - [XPath tests 983] - expected: FAIL - - [XPath tests 984] - expected: FAIL - - [XPath tests 985] - expected: FAIL - - [XPath tests 986] - expected: FAIL - - [XPath tests 987] - expected: FAIL - - [XPath tests 988] - expected: FAIL - - [XPath tests 989] - expected: FAIL - - [XPath tests 990] - expected: FAIL - - [XPath tests 991] - expected: FAIL - - [XPath tests 992] - expected: FAIL - - [XPath tests 993] - expected: FAIL - - [XPath tests 994] - expected: FAIL - - [XPath tests 995] - expected: FAIL - - [XPath tests 996] - expected: FAIL - - [XPath tests 997] - expected: FAIL - - [XPath tests 998] - expected: FAIL - - [XPath tests 999] - expected: FAIL - - [XPath tests 1000] - expected: FAIL - - [XPath tests 1001] - expected: FAIL - - [XPath tests 1002] - expected: FAIL - - [XPath tests 1003] - expected: FAIL - - [XPath tests 1004] - expected: FAIL - - [XPath tests 1005] - expected: FAIL - - [XPath tests 1006] - expected: FAIL - - [XPath tests 1007] - expected: FAIL - - [XPath tests 1008] - expected: FAIL - - [XPath tests 1009] - expected: FAIL - - [XPath tests 1010] - expected: FAIL - - [XPath tests 1011] - expected: FAIL - - [XPath tests 1012] - expected: FAIL - - [XPath tests 1013] - expected: FAIL - - [XPath tests 1014] - expected: FAIL - - [XPath tests 1015] - expected: FAIL - - [XPath tests 1016] - expected: FAIL - - [XPath tests 1017] - expected: FAIL - - [XPath tests 1018] - expected: FAIL - - [XPath tests 1019] - expected: FAIL - - [XPath tests 1020] - expected: FAIL - - [XPath tests 1021] - expected: FAIL - - [XPath tests 1022] - expected: FAIL - - [XPath tests 1023] - expected: FAIL diff --git a/tests/wpt/meta/fetch/content-encoding/br/bad-br-body.https.any.js.ini b/tests/wpt/meta/fetch/content-encoding/br/bad-br-body.https.any.js.ini index 2a7f8c45be1..16e5901cca3 100644 --- a/tests/wpt/meta/fetch/content-encoding/br/bad-br-body.https.any.js.ini +++ b/tests/wpt/meta/fetch/content-encoding/br/bad-br-body.https.any.js.ini @@ -1,3 +1,15 @@ [bad-br-body.https.any.html] [Consuming the body of a resource with bad br content with arrayBuffer() should reject] expected: FAIL + + [Consuming the body of a resource with bad br content with blob() should reject] + expected: FAIL + + [Consuming the body of a resource with bad br content with bytes() should reject] + expected: FAIL + + [Consuming the body of a resource with bad br content with json() should reject] + expected: FAIL + + [Consuming the body of a resource with bad br content with text() should reject] + expected: FAIL diff --git a/tests/wpt/meta/fetch/content-encoding/gzip/bad-gzip-body.any.js.ini b/tests/wpt/meta/fetch/content-encoding/gzip/bad-gzip-body.any.js.ini index 24a7b7bcc7f..aec86e6cdb2 100644 --- a/tests/wpt/meta/fetch/content-encoding/gzip/bad-gzip-body.any.js.ini +++ b/tests/wpt/meta/fetch/content-encoding/gzip/bad-gzip-body.any.js.ini @@ -11,6 +11,9 @@ [Consuming the body of a resource with bad gzip content with text() should reject] expected: FAIL + [Consuming the body of a resource with bad gzip content with bytes() should reject] + expected: FAIL + [bad-gzip-body.any.worker.html] [Consuming the body of a resource with bad gzip content with arrayBuffer() should reject] @@ -25,6 +28,9 @@ [Consuming the body of a resource with bad gzip content with text() should reject] expected: FAIL + [Consuming the body of a resource with bad gzip content with bytes() should reject] + expected: FAIL + [bad-gzip-body.any.serviceworker.html] expected: ERROR diff --git a/tests/wpt/meta/fetch/content-encoding/zstd/bad-zstd-body.https.any.js.ini b/tests/wpt/meta/fetch/content-encoding/zstd/bad-zstd-body.https.any.js.ini index ed17fcbaf81..121ae28c821 100644 --- a/tests/wpt/meta/fetch/content-encoding/zstd/bad-zstd-body.https.any.js.ini +++ b/tests/wpt/meta/fetch/content-encoding/zstd/bad-zstd-body.https.any.js.ini @@ -11,6 +11,9 @@ [Consuming the body of a resource with bad zstd content with text() should reject] expected: FAIL + [Consuming the body of a resource with bad zstd content with bytes() should reject] + expected: FAIL + [bad-zstd-body.https.any.worker.html] [Consuming the body of a resource with bad zstd content with arrayBuffer() should reject] @@ -25,6 +28,9 @@ [Consuming the body of a resource with bad zstd content with text() should reject] expected: FAIL + [Consuming the body of a resource with bad zstd content with bytes() should reject] + expected: FAIL + [bad-zstd-body.https.any.sharedworker.html] expected: ERROR diff --git a/tests/wpt/meta/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini b/tests/wpt/meta/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini index 77fa4b61164..46f58cc786e 100644 --- a/tests/wpt/meta/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini +++ b/tests/wpt/meta/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini @@ -33,9 +33,6 @@ [Https downgrade-upgrade embed] expected: TIMEOUT - [Https downgrade-upgrade preload] - expected: TIMEOUT - [Https downgrade-upgrade iframe: sec-fetch-mode] expected: FAIL diff --git a/tests/wpt/meta/fetch/nosniff/importscripts.html.ini b/tests/wpt/meta/fetch/nosniff/importscripts.html.ini deleted file mode 100644 index 50d9a81d542..00000000000 --- a/tests/wpt/meta/fetch/nosniff/importscripts.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[importscripts.html] - expected: ERROR - [Test importScripts()] - expected: TIMEOUT diff --git a/tests/wpt/meta/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js.ini b/tests/wpt/meta/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js.ini deleted file mode 100644 index 695ae5a48a0..00000000000 --- a/tests/wpt/meta/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js.ini +++ /dev/null @@ -1,156 +0,0 @@ -[mixed-content-fetch.tentative.https.window.html] - [https-local to http-local: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-local to http-local: wrong targetAddressSpace "private".] - expected: FAIL - - [https-local to http-local: wrong targetAddressSpace "public".] - expected: FAIL - - [https-local to http-local: not a private network request.] - expected: FAIL - - [https-local to http-private: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-local to http-private: wrong targetAddressSpace "local".] - expected: FAIL - - [https-local to http-private: wrong targetAddressSpace "public".] - expected: FAIL - - [https-local to http-private: not a private network request.] - expected: FAIL - - [https-local to http-public: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-local to http-public: wrong targetAddressSpace "local".] - expected: FAIL - - [https-local to http-public: wrong targetAddressSpace "private".] - expected: FAIL - - [https-local to http-public: not a private network request.] - expected: FAIL - - [https-private to http-local: missing targetAddressSpace.] - expected: FAIL - - [https-private to http-local: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-private to http-local: wrong targetAddressSpace "private".] - expected: FAIL - - [https-private to http-local: wrong targetAddressSpace "public".] - expected: FAIL - - [https-private to http-local: failed preflight.] - expected: FAIL - - [https-private to http-local: success.] - expected: FAIL - - [https-private to http-private: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-private to http-private: wrong targetAddressSpace "local".] - expected: FAIL - - [https-private to http-private: wrong targetAddressSpace "public".] - expected: FAIL - - [https-private to http-private: not a private network request.] - expected: FAIL - - [https-private to http-public: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-private to http-public: wrong targetAddressSpace "local".] - expected: FAIL - - [https-private to http-public: wrong targetAddressSpace "private".] - expected: FAIL - - [https-private to http-public: not a private network request.] - expected: FAIL - - [https-public to http-local: missing targetAddressSpace.] - expected: FAIL - - [https-public to http-local: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-public to http-local: wrong targetAddressSpace "private".] - expected: FAIL - - [https-public to http-local: wrong targetAddressSpace "public".] - expected: FAIL - - [https-public to http-local: failed preflight.] - expected: FAIL - - [https-public to http-local: success.] - expected: FAIL - - [https-public to http-private: missing targetAddressSpace.] - expected: FAIL - - [https-public to http-private: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-public to http-private: wrong targetAddressSpace "local".] - expected: FAIL - - [https-public to http-private: wrong targetAddressSpace "public".] - expected: FAIL - - [https-public to http-private: failed preflight.] - expected: FAIL - - [https-public to http-private: success.] - expected: FAIL - - [https-public to http-public: wrong targetAddressSpace "unknown".] - expected: FAIL - - [https-public to http-public: wrong targetAddressSpace "local".] - expected: FAIL - - [https-public to http-public: wrong targetAddressSpace "private".] - expected: FAIL - - [https-public to http-public: not a private network request.] - expected: FAIL - - [https-treat-as-public to http-local: wrong targetAddressSpace "private".] - expected: FAIL - - [https-treat-as-public to http-private: wrong targetAddressSpace "local".] - expected: FAIL - - [https-treat-as-public to http-private: success.] - expected: FAIL - - [https-private to http-local: PUT success.] - expected: FAIL - - [https-private to http-local: no-cors success.] - expected: FAIL - - [https-public to http-local: PUT success.] - expected: FAIL - - [https-public to http-local: no-cors success.] - expected: FAIL - - [https-public to http-private: PUT success.] - expected: FAIL - - [https-public to http-private: no-cors success.] - expected: FAIL - - [https-treat-as-public to http-local: success.] - expected: FAIL diff --git a/tests/wpt/meta/fetch/private-network-access/window-open-existing.tentative.https.window.js.ini b/tests/wpt/meta/fetch/private-network-access/window-open-existing.tentative.https.window.js.ini deleted file mode 100644 index 6bcaf322518..00000000000 --- a/tests/wpt/meta/fetch/private-network-access/window-open-existing.tentative.https.window.js.ini +++ /dev/null @@ -1,72 +0,0 @@ -[window-open-existing.tentative.https.window.html?include=from-treat-as-public] - [treat-as-public-address to local: failed preflight.] - expected: FAIL - - [treat-as-public-address to local: missing CORS headers.] - expected: FAIL - - [treat-as-public-address to local: missing PNA header.] - expected: FAIL - - [treat-as-public-address to local: success.] - expected: FAIL - - [treat-as-public-address to private: failed preflight.] - expected: FAIL - - [treat-as-public-address to private: missing CORS headers.] - expected: FAIL - - [treat-as-public-address to private: missing PNA header.] - expected: FAIL - - [treat-as-public-address to private: success.] - expected: FAIL - - -[window-open-existing.tentative.https.window.html?include=from-public] - [public to local: failed preflight.] - expected: FAIL - - [public to local: missing CORS headers.] - expected: FAIL - - [public to local: missing PNA header.] - expected: FAIL - - [public to local: success.] - expected: FAIL - - [public to private: failed preflight.] - expected: FAIL - - [public to private: missing CORS headers.] - expected: FAIL - - [public to private: missing PNA header.] - expected: FAIL - - [public to private: success.] - expected: FAIL - - [public to public redirected to private: missing CORS headers.] - expected: FAIL - - [public to public to private: success.] - expected: FAIL - - -[window-open-existing.tentative.https.window.html?include=from-local] - -[window-open-existing.tentative.https.window.html?include=from-private] - [private to local: failed preflight.] - expected: FAIL - - [private to local: missing CORS headers.] - expected: FAIL - - [private to local: missing PNA header.] - expected: FAIL - - [private to local: success.] - expected: FAIL diff --git a/tests/wpt/meta/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html.ini b/tests/wpt/meta/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html.ini new file mode 100644 index 00000000000..1740303b284 --- /dev/null +++ b/tests/wpt/meta/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html.ini @@ -0,0 +1,3 @@ +[focus-contenteditable-element-in-iframe-scroll-into-view.html] + [Check contenteditable element in an iframe scroll into view on second focusing] + expected: FAIL diff --git a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/008.html.ini b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/008.html.ini deleted file mode 100644 index c253f779d78..00000000000 --- a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/008.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[008.html] - [Link with onclick form submit to javascript url and href navigation ] - expected: FAIL diff --git a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/009.html.ini b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/009.html.ini new file mode 100644 index 00000000000..3fb21c9b2c6 --- /dev/null +++ b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/009.html.ini @@ -0,0 +1,3 @@ +[009.html] + [Link with onclick form submit to javascript url with document.write and href navigation ] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/set_timeouts/set.py.ini b/tests/wpt/meta/html/browsers/history/the-history-interface/001.html.ini index bfc9d7723d9..b0bdba7f308 100644 --- a/tests/wpt/meta/webdriver/tests/classic/set_timeouts/set.py.ini +++ b/tests/wpt/meta/html/browsers/history/the-history-interface/001.html.ini @@ -1,2 +1,2 @@ -[set.py] +[001.html] expected: TIMEOUT diff --git a/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini new file mode 100644 index 00000000000..a03a8322165 --- /dev/null +++ b/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini @@ -0,0 +1,3 @@ +[traverse_the_history_3.html] + [Multiple history traversals, last would be aborted] + expected: FAIL diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini index d7226bfed74..0420669cc09 100644 --- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini +++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini @@ -1,5 +1,4 @@ [createImageBitmap-origin.sub.html] - expected: TIMEOUT [redirected to cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage] expected: FAIL diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini index 20be1f3b9e5..495a1789274 100644 --- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini +++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-transfer.html.ini @@ -1,4 +1,5 @@ [createImageBitmap-transfer.html] + expected: ERROR [Transfer ImageBitmap created from a vector HTMLImageElement] expected: FAIL diff --git a/tests/wpt/meta/html/dom/idlharness.https.html.ini b/tests/wpt/meta/html/dom/idlharness.https.html.ini index 81d2aa5b8a5..b2ea5b118c1 100644 --- a/tests/wpt/meta/html/dom/idlharness.https.html.ini +++ b/tests/wpt/meta/html/dom/idlharness.https.html.ini @@ -5455,18 +5455,6 @@ [HTMLHeadingElement interface: document.createElement("h1") must inherit property "align" with the proper type] expected: FAIL - [HTMLHRElement interface: attribute noShade] - expected: FAIL - - [HTMLHRElement interface: attribute size] - expected: FAIL - - [HTMLHRElement interface: document.createElement("hr") must inherit property "noShade" with the proper type] - expected: FAIL - - [HTMLHRElement interface: document.createElement("hr") must inherit property "size" with the proper type] - expected: FAIL - [HTMLOListElement interface: attribute reversed] expected: FAIL diff --git a/tests/wpt/meta/html/dom/reflection-grouping.html.ini b/tests/wpt/meta/html/dom/reflection-grouping.html.ini index 556eea039e9..ec7075bc5ab 100644 --- a/tests/wpt/meta/html/dom/reflection-grouping.html.ini +++ b/tests/wpt/meta/html/dom/reflection-grouping.html.ini @@ -383,234 +383,6 @@ [hr.tabIndex: IDL set to -2147483648] expected: FAIL - [hr.noShade: typeof IDL attribute] - expected: FAIL - - [hr.noShade: IDL get with DOM attribute unset] - expected: FAIL - - [hr.noShade: setAttribute() to ""] - expected: FAIL - - [hr.noShade: setAttribute() to " foo "] - expected: FAIL - - [hr.noShade: setAttribute() to undefined] - expected: FAIL - - [hr.noShade: setAttribute() to null] - expected: FAIL - - [hr.noShade: setAttribute() to 7] - expected: FAIL - - [hr.noShade: setAttribute() to 1.5] - expected: FAIL - - [hr.noShade: setAttribute() to "5%"] - expected: FAIL - - [hr.noShade: setAttribute() to "+100"] - expected: FAIL - - [hr.noShade: setAttribute() to ".5"] - expected: FAIL - - [hr.noShade: setAttribute() to true] - expected: FAIL - - [hr.noShade: setAttribute() to false] - expected: FAIL - - [hr.noShade: setAttribute() to object "[object Object\]"] - expected: FAIL - - [hr.noShade: setAttribute() to NaN] - expected: FAIL - - [hr.noShade: setAttribute() to Infinity] - expected: FAIL - - [hr.noShade: setAttribute() to -Infinity] - expected: FAIL - - [hr.noShade: setAttribute() to "\\0"] - expected: FAIL - - [hr.noShade: setAttribute() to object "test-toString"] - expected: FAIL - - [hr.noShade: setAttribute() to object "test-valueOf"] - expected: FAIL - - [hr.noShade: setAttribute() to "noShade"] - expected: FAIL - - [hr.noShade: IDL set to ""] - expected: FAIL - - [hr.noShade: IDL set to " foo "] - expected: FAIL - - [hr.noShade: IDL set to undefined] - expected: FAIL - - [hr.noShade: IDL set to null] - expected: FAIL - - [hr.noShade: IDL set to 7] - expected: FAIL - - [hr.noShade: IDL set to 1.5] - expected: FAIL - - [hr.noShade: IDL set to "5%"] - expected: FAIL - - [hr.noShade: IDL set to "+100"] - expected: FAIL - - [hr.noShade: IDL set to ".5"] - expected: FAIL - - [hr.noShade: IDL set to false] - expected: FAIL - - [hr.noShade: IDL set to object "[object Object\]"] - expected: FAIL - - [hr.noShade: IDL set to NaN] - expected: FAIL - - [hr.noShade: IDL set to Infinity] - expected: FAIL - - [hr.noShade: IDL set to -Infinity] - expected: FAIL - - [hr.noShade: IDL set to "\\0"] - expected: FAIL - - [hr.noShade: IDL set to object "test-toString"] - expected: FAIL - - [hr.noShade: IDL set to object "test-valueOf"] - expected: FAIL - - [hr.size: typeof IDL attribute] - expected: FAIL - - [hr.size: IDL get with DOM attribute unset] - expected: FAIL - - [hr.size: setAttribute() to ""] - expected: FAIL - - [hr.size: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] - expected: FAIL - - [hr.size: setAttribute() to undefined] - expected: FAIL - - [hr.size: setAttribute() to 7] - expected: FAIL - - [hr.size: setAttribute() to 1.5] - expected: FAIL - - [hr.size: setAttribute() to "5%"] - expected: FAIL - - [hr.size: setAttribute() to "+100"] - expected: FAIL - - [hr.size: setAttribute() to ".5"] - expected: FAIL - - [hr.size: setAttribute() to true] - expected: FAIL - - [hr.size: setAttribute() to false] - expected: FAIL - - [hr.size: setAttribute() to object "[object Object\]"] - expected: FAIL - - [hr.size: setAttribute() to NaN] - expected: FAIL - - [hr.size: setAttribute() to Infinity] - expected: FAIL - - [hr.size: setAttribute() to -Infinity] - expected: FAIL - - [hr.size: setAttribute() to "\\0"] - expected: FAIL - - [hr.size: setAttribute() to null] - expected: FAIL - - [hr.size: setAttribute() to object "test-toString"] - expected: FAIL - - [hr.size: setAttribute() to object "test-valueOf"] - expected: FAIL - - [hr.size: IDL set to ""] - expected: FAIL - - [hr.size: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo "] - expected: FAIL - - [hr.size: IDL set to undefined] - expected: FAIL - - [hr.size: IDL set to 7] - expected: FAIL - - [hr.size: IDL set to 1.5] - expected: FAIL - - [hr.size: IDL set to "5%"] - expected: FAIL - - [hr.size: IDL set to "+100"] - expected: FAIL - - [hr.size: IDL set to ".5"] - expected: FAIL - - [hr.size: IDL set to true] - expected: FAIL - - [hr.size: IDL set to false] - expected: FAIL - - [hr.size: IDL set to object "[object Object\]"] - expected: FAIL - - [hr.size: IDL set to NaN] - expected: FAIL - - [hr.size: IDL set to Infinity] - expected: FAIL - - [hr.size: IDL set to -Infinity] - expected: FAIL - - [hr.size: IDL set to "\\0"] - expected: FAIL - - [hr.size: IDL set to null] - expected: FAIL - - [hr.size: IDL set to object "test-toString"] - expected: FAIL - - [hr.size: IDL set to object "test-valueOf"] - expected: FAIL - [pre.accessKey: typeof IDL attribute] expected: FAIL diff --git a/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini b/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini deleted file mode 100644 index dbbc149ee4a..00000000000 --- a/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[media_fragment_seek.html] - expected: CRASH diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini index 24903b5f66f..d7e7d1b9815 100644 --- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini +++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini @@ -1,4 +1,4 @@ [iframe_sandbox_popups_escaping-1.html] - expected: TIMEOUT + expected: CRASH [Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used] expected: TIMEOUT diff --git a/tests/wpt/meta/html/semantics/permission-element/negative-offset-and-margin.tentative.html.ini b/tests/wpt/meta/html/semantics/permission-element/negative-offset-and-margin.tentative.html.ini deleted file mode 100644 index 75e70650007..00000000000 --- a/tests/wpt/meta/html/semantics/permission-element/negative-offset-and-margin.tentative.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[negative-offset-and-margin.tentative.html] - [Negative margins/offset should be changed to 0px] - expected: FAIL - - [Expressions margins/offset should always return at least 0px] - expected: FAIL - - [Negative margins/offset should be changed to 4px] - expected: FAIL - - [Expressions margins/offset should always return at least 4px] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/permission-element/negative-offset.tentative.html.ini b/tests/wpt/meta/html/semantics/permission-element/negative-offset.tentative.html.ini new file mode 100644 index 00000000000..74386d1c491 --- /dev/null +++ b/tests/wpt/meta/html/semantics/permission-element/negative-offset.tentative.html.ini @@ -0,0 +1,9 @@ +[negative-offset.tentative.html] + [Negative offset should be changed to 0px] + expected: FAIL + + [Expressions offset min(-50px, 50px) should return at least 0px] + expected: FAIL + + [Expressions offset clamp(-100px, 1vw, -50px) should return at least 0px] + expected: FAIL diff --git a/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html.ini b/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html.ini new file mode 100644 index 00000000000..bc9fdd0cbaf --- /dev/null +++ b/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html.ini @@ -0,0 +1,2 @@ +[icon-hidden-reftest.html] + expected: FAIL diff --git a/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html.ini b/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html.ini new file mode 100644 index 00000000000..248944bc32e --- /dev/null +++ b/tests/wpt/meta/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html.ini @@ -0,0 +1,2 @@ +[icon-unique-per-type-reftest.html] + expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/042.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/042.html.ini deleted file mode 100644 index 6c2be5a1ab2..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/042.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[042.html] - [ scheduler: DOM mutation events when adding scripts: DOMNodeInserted ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/043.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/043.html.ini deleted file mode 100644 index 83a6a3fb2a9..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/043.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[043.html] - [ scheduler: DOM mutation events when adding external scripts: DOMNodeInserted ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/044.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/044.html.ini deleted file mode 100644 index 4e428ec9a29..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/044.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[044.html] - [ scheduler: DOM mutation events when adding scripts: DOMNodeInsertedIntoDocument ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/045.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/045.html.ini deleted file mode 100644 index b5409fbb4ac..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/045.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[045.html] - [ scheduler: DOM mutation events when adding external scripts: DOMNodeInsertedIntoDocument ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/054.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/054.html.ini deleted file mode 100644 index abdc47b56ae..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/054.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[054.html] - [ scheduler: removing newly inserted script from DOMNodeInserted handler - external script ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/055.html.ini b/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/055.html.ini deleted file mode 100644 index af2467b3e71..00000000000 --- a/tests/wpt/meta/html/semantics/scripting-1/the-script-element/execution-timing/055.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[055.html] - [ scheduler: removing newly inserted script from DOMNodeInserted handler - inline script ] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html.ini b/tests/wpt/meta/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html.ini new file mode 100644 index 00000000000..c882098a91c --- /dev/null +++ b/tests/wpt/meta/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html.ini @@ -0,0 +1,9 @@ +[source-attribute-retargeting.tentative.html] + [CommandEvent.source and ToggleEvent.source should be retargeted during and after event dispatch.] + expected: FAIL + + [CommandEvent.source should be retargeted when manually dispatched with composed set to true.] + expected: FAIL + + [CommandEvent.source and ToggleEvent.source should not be set to null after dispatch without ShadowDOM.] + expected: FAIL diff --git a/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini b/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini index 20d32f43049..484aa044de7 100644 --- a/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini +++ b/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini @@ -16,3 +16,15 @@ [Reload fetchStart > Original fetchStart] expected: FAIL + + [Reload domComplete > Original domComplete] + expected: FAIL + + [Reload domContentLoadedEventEnd > Original domContentLoadedEventEnd] + expected: FAIL + + [Reload loadEventEnd > Original loadEventEnd] + expected: FAIL + + [Reload loadEventStart > Original loadEventStart] + expected: FAIL diff --git a/tests/wpt/meta/preload/preload-error.sub.html.ini b/tests/wpt/meta/preload/preload-error.sub.html.ini index 11cddb179c3..f383c31f2fd 100644 --- a/tests/wpt/meta/preload/preload-error.sub.html.ini +++ b/tests/wpt/meta/preload/preload-error.sub.html.ini @@ -5,36 +5,24 @@ [CORS-error (image): main] expected: FAIL - [CSP-error (image): preload events] - expected: FAIL - [CSP-error (image): main] expected: FAIL [CORS-error (style): main] expected: FAIL - [CSP-error (style): preload events] - expected: FAIL - [CSP-error (style): main] expected: FAIL [CORS-error (script): main] expected: FAIL - [CSP-error (script): preload events] - expected: FAIL - [CSP-error (script): main] expected: FAIL [CORS-error (xhr): main] expected: FAIL - [CSP-error (xhr): preload events] - expected: FAIL - [CSP-error (xhr): main] expected: FAIL @@ -50,9 +38,6 @@ [CORS-error (fetch): main] expected: FAIL - [CSP-error (fetch): preload events] - expected: FAIL - [CSP-error (fetch): main] expected: FAIL diff --git a/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini b/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini new file mode 100644 index 00000000000..5d07f60e0b6 --- /dev/null +++ b/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini @@ -0,0 +1,3 @@ +[change-layout-in-error.html] + [Changing layout in window error handler should not result in lifecyle loop when resize observer loop limit is reached.] + expected: FAIL diff --git a/tests/wpt/meta/resize-observer/zoom.html.ini b/tests/wpt/meta/resize-observer/zoom.html.ini new file mode 100644 index 00000000000..a08a15e7c82 --- /dev/null +++ b/tests/wpt/meta/resize-observer/zoom.html.ini @@ -0,0 +1,3 @@ +[zoom.html] + [ResizeObserver sizes account for zoom] + expected: FAIL diff --git a/tests/wpt/meta/trusted-types/block-text-node-insertion-into-script-element.html.ini b/tests/wpt/meta/trusted-types/block-text-node-insertion-into-script-element.html.ini index 34f64b9ef70..366c956d411 100644 --- a/tests/wpt/meta/trusted-types/block-text-node-insertion-into-script-element.html.ini +++ b/tests/wpt/meta/trusted-types/block-text-node-insertion-into-script-element.html.ini @@ -17,3 +17,12 @@ [Spot tests around script + innerHTML interaction with default policy.] expected: FAIL + + [Regression test: Bypass via appendChild into off-document script element.] + expected: FAIL + + [Regression test: Bypass via appendChild into live script element.] + expected: FAIL + + [Test that default policy applies to module script.] + expected: FAIL diff --git a/tests/wpt/meta/trusted-types/block-text-node-insertion-into-svg-script-element.html.ini b/tests/wpt/meta/trusted-types/block-text-node-insertion-into-svg-script-element.html.ini index e0fbb2a6064..4d469799e85 100644 --- a/tests/wpt/meta/trusted-types/block-text-node-insertion-into-svg-script-element.html.ini +++ b/tests/wpt/meta/trusted-types/block-text-node-insertion-into-svg-script-element.html.ini @@ -10,3 +10,6 @@ [Spot tests around script + innerHTML interaction with default policy.] expected: FAIL + + [Test that default policy applies with module script. svg:script] + expected: FAIL diff --git a/tests/wpt/meta/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html.ini b/tests/wpt/meta/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html.ini deleted file mode 100644 index e36472cb628..00000000000 --- a/tests/wpt/meta/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[ProcessingInstruction.DOMCharacterDataModified.html] - [Test Description: DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified, but the node itself has not been inserted or deleted. The proximal event target of this event shall be the ProcessingInstruction node.] - expected: FAIL diff --git a/tests/wpt/meta/uievents/legacy-domevents-tests/approved/domnodeinserted.html.ini b/tests/wpt/meta/uievents/legacy-domevents-tests/approved/domnodeinserted.html.ini deleted file mode 100644 index 27f8ad9e90f..00000000000 --- a/tests/wpt/meta/uievents/legacy-domevents-tests/approved/domnodeinserted.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[domnodeinserted.html] - expected: TIMEOUT - [Test Description: DOMNodeInserted event fires when a node has been added as a child of another node.] - expected: NOTRUN diff --git a/tests/wpt/meta/urlpattern/urlpattern-generate.tentative.any.js.ini b/tests/wpt/meta/urlpattern/urlpattern-generate.tentative.any.js.ini new file mode 100644 index 00000000000..3c01bdb3c49 --- /dev/null +++ b/tests/wpt/meta/urlpattern/urlpattern-generate.tentative.any.js.ini @@ -0,0 +1,63 @@ +[urlpattern-generate.tentative.any.worker.html] + [Pattern: {"pathname":"/foo"} Component: pathname Groups: {}] + expected: FAIL + + [Pattern: {"pathname":"/:foo"} Component: pathname Groups: {"foo":"bar"}] + expected: FAIL + + [Pattern: {"pathname":"/:foo"} Component: pathname Groups: {"foo":"🍅"}] + expected: FAIL + + [Pattern: {"hostname":"{:foo}.example.com"} Component: hostname Groups: {"foo":"🍅"}] + expected: FAIL + + [Pattern: {"pathname":"/foo/:bar"} Component: pathname Groups: {"bar":"baz"}] + expected: FAIL + + [Pattern: {"pathname":"/foo:bar"} Component: pathname Groups: {"bar":"baz"}] + expected: FAIL + + [Pattern: {"pathname":"/:foo/:bar"} Component: pathname Groups: {"foo":"baz","bar":"qux"}] + expected: FAIL + + [Pattern: "https://example.com/:foo" Component: pathname Groups: {"foo":" "}] + expected: FAIL + + [Pattern: "original-scheme://example.com/:foo" Component: pathname Groups: {"foo":" "}] + expected: FAIL + + +[urlpattern-generate.tentative.any.html] + [Pattern: {"pathname":"/foo"} Component: pathname Groups: {}] + expected: FAIL + + [Pattern: {"pathname":"/:foo"} Component: pathname Groups: {"foo":"bar"}] + expected: FAIL + + [Pattern: {"pathname":"/:foo"} Component: pathname Groups: {"foo":"🍅"}] + expected: FAIL + + [Pattern: {"hostname":"{:foo}.example.com"} Component: hostname Groups: {"foo":"🍅"}] + expected: FAIL + + [Pattern: {"pathname":"/foo/:bar"} Component: pathname Groups: {"bar":"baz"}] + expected: FAIL + + [Pattern: {"pathname":"/foo:bar"} Component: pathname Groups: {"bar":"baz"}] + expected: FAIL + + [Pattern: {"pathname":"/:foo/:bar"} Component: pathname Groups: {"foo":"baz","bar":"qux"}] + expected: FAIL + + [Pattern: "https://example.com/:foo" Component: pathname Groups: {"foo":" "}] + expected: FAIL + + [Pattern: "original-scheme://example.com/:foo" Component: pathname Groups: {"foo":" "}] + expected: FAIL + + +[urlpattern-generate.tentative.any.serviceworker.html] + expected: ERROR + +[urlpattern-generate.tentative.any.sharedworker.html] + expected: ERROR diff --git a/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini b/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini index 960779501c4..5d66c9ba352 100644 --- a/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini +++ b/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini @@ -805,3 +805,12 @@ [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[14650\]\t2.4329547374028208e-17\t8.6956524848937988e-1\t8.6956524848937988e-1\t1.0000000000000000e+0\t3.8985999999999999e-3\n\t[14651\]\t3.0547976493835449e-1\t8.9879405498504639e-1\t5.9331429004669189e-1\t6.6012262403823208e-1\t3.8985999999999999e-3\n\tMax AbsError of 8.6956524848937988e-1 at index of 14650.\n\tMax RelError of 1.0000000000000000e+0 at index of 14650.\n] expected: FAIL + + [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[14650\]\t3.3752832548824226e-34\t8.6956524848937988e-1\t8.6956524848937988e-1\t1.0000000000000000e+0\t3.8985999999999999e-3\n\t[14651\]\t3.0547976493835449e-1\t8.9879405498504639e-1\t5.9331429004669189e-1\t6.6012262403823208e-1\t3.8985999999999999e-3\n\tMax AbsError of 8.6956524848937988e-1 at index of 14650.\n\tMax RelError of 1.0000000000000000e+0 at index of 14650.\n] + expected: FAIL + + [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[14650\]\t4.5710336303710938e+2\t8.6956524848937988e-1\t4.5623379778862000e+2\t5.2466884869329283e+2\t3.8985999999999999e-3\n\t[14651\]\t3.0547976493835449e-1\t8.9879405498504639e-1\t5.9331429004669189e-1\t6.6012262403823208e-1\t3.8985999999999999e-3\n\tMax AbsError of 4.5623379778862000e+2 at index of 14650.\n\tMax RelError of 5.2466884869329283e+2 at index of 14650.\n] + expected: FAIL + + [X SNR (-9.749670615505378 dB) is not greater than or equal to 65.737. Got -9.749670615505378.] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/accept_alert/accept.py.ini b/tests/wpt/meta/webdriver/tests/classic/accept_alert/accept.py.ini index 00caf69c8d5..a5d10aa6fe2 100644 --- a/tests/wpt/meta/webdriver/tests/classic/accept_alert/accept.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/accept_alert/accept.py.ini @@ -1,4 +1,5 @@ [accept.py] + expected: TIMEOUT [test_null_response_value] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/dismiss_alert/dismiss.py.ini b/tests/wpt/meta/webdriver/tests/classic/dismiss_alert/dismiss.py.ini index cd2546ede8b..a2869095ca8 100644 --- a/tests/wpt/meta/webdriver/tests/classic/dismiss_alert/dismiss.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/dismiss_alert/dismiss.py.ini @@ -1,4 +1,5 @@ [dismiss.py] + expected: TIMEOUT [test_no_top_browsing_context] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_clear/clear.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_clear/clear.py.ini index 541ffc25ca6..6a82e9170b8 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_clear/clear.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_clear/clear.py.ini @@ -1,2 +1,210 @@ [clear.py] - expected: TIMEOUT + [test_null_response_value] + expected: FAIL + + [test_no_top_browsing_context] + expected: FAIL + + [test_no_browsing_context] + expected: FAIL + + [test_no_such_element_with_invalid_value] + expected: FAIL + + [test_no_such_element_with_shadow_root] + expected: FAIL + + [test_no_such_element_from_other_window_handle[open\]] + expected: FAIL + + [test_no_such_element_from_other_window_handle[closed\]] + expected: FAIL + + [test_no_such_element_from_other_frame[open\]] + expected: FAIL + + [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_pointer_interactable] + expected: FAIL + + [test_keyboard_interactable] + expected: FAIL + + [test_input[number-42-\]] + expected: FAIL + + [test_input[range-42-50\]] + expected: FAIL + + [test_input[email-foo@example.com-\]] + expected: FAIL + + [test_input[password-password-\]] + expected: FAIL + + [test_input[search-search-\]] + expected: FAIL + + [test_input[tel-999-\]] + expected: FAIL + + [test_input[text-text-\]] + expected: FAIL + + [test_input[url-https://example.com/-\]] + expected: FAIL + + [test_input[color-#ff0000-#000000\]] + expected: FAIL + + [test_input[date-2017-12-26-\]] + expected: FAIL + + [test_input[datetime-2017-12-26T19:48-\]] + expected: FAIL + + [test_input[datetime-local-2017-12-26T19:48-\]] + expected: FAIL + + [test_input[time-19:48-\]] + expected: FAIL + + [test_input[month-2017-11-\]] + expected: FAIL + + [test_input[week-2017-W52-\]] + expected: FAIL + + [test_input_readonly[number\]] + expected: FAIL + + [test_input_readonly[range\]] + expected: FAIL + + [test_input_readonly[email\]] + expected: FAIL + + [test_input_readonly[password\]] + expected: FAIL + + [test_input_readonly[search\]] + expected: FAIL + + [test_input_readonly[tel\]] + expected: FAIL + + [test_input_readonly[text\]] + expected: FAIL + + [test_input_readonly[url\]] + expected: FAIL + + [test_input_readonly[color\]] + expected: FAIL + + [test_input_readonly[date\]] + expected: FAIL + + [test_input_readonly[datetime\]] + expected: FAIL + + [test_input_readonly[datetime-local\]] + expected: FAIL + + [test_input_readonly[time\]] + expected: FAIL + + [test_input_readonly[month\]] + expected: FAIL + + [test_input_readonly[week\]] + expected: FAIL + + [test_input_readonly[file\]] + expected: FAIL + + [test_textarea] + expected: FAIL + + [test_textarea_readonly] + expected: FAIL + + [test_input_file] + expected: FAIL + + [test_input_file_multiple] + expected: FAIL + + [test_button[button\]] + expected: FAIL + + [test_button[reset\]] + expected: FAIL + + [test_button[submit\]] + expected: FAIL + + [test_button_with_subtree] + expected: FAIL + + [test_contenteditable] + expected: FAIL + + [test_designmode] + expected: FAIL + + [test_resettable_element_focus_when_empty] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[number-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[email-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[url-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[date-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[datetime-local-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[time-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[month-foo\]] + expected: FAIL + + [test_resettable_element_does_not_satisfy_validation_constraints[week-foo\]] + expected: FAIL + + [test_non_editable_inputs[checkbox\]] + expected: FAIL + + [test_non_editable_inputs[radio\]] + expected: FAIL + + [test_non_editable_inputs[hidden\]] + expected: FAIL + + [test_non_editable_inputs[submit\]] + expected: FAIL + + [test_non_editable_inputs[button\]] + expected: FAIL + + [test_non_editable_inputs[image\]] + expected: FAIL + + [test_scroll_into_view] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_clear/disabled.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_clear/disabled.py.ini index f6367167d66..76b124f1dca 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_clear/disabled.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_clear/disabled.py.ini @@ -1,5 +1,4 @@ [disabled.py] - expected: TIMEOUT [test_button[button\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/bubbling.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/bubbling.py.ini deleted file mode 100644 index d99f3672ef6..00000000000 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/bubbling.py.ini +++ /dev/null @@ -1,6 +0,0 @@ -[bubbling.py] - [test_click_event_bubbles_to_parents] - expected: FAIL - - [test_spin_event_loop] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/center_point.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/center_point.py.ini index 3e3bfa2708e..48358dc41c1 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/center_point.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_click/center_point.py.ini @@ -1,4 +1,5 @@ [center_point.py] + expected: TIMEOUT [test_entirely_in_view] 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 9cdf1e0d0da..7405df1cdfb 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 @@ -7,9 +7,3 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/events.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/events.py.ini deleted file mode 100644 index 8f57d96cef8..00000000000 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/events.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[events.py] - [test_event_mousemove] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/interactability.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/interactability.py.ini index 982ea5ca753..9c185c61557 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/interactability.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_click/interactability.py.ini @@ -1,4 +1,5 @@ [interactability.py] + expected: TIMEOUT [test_display_none] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini index 92d8bfe9a3d..32fd2854998 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini @@ -2,14 +2,8 @@ [test_shadow_element_click[host_element\]] expected: FAIL - [test_shadow_element_click[checkbox_element\]] - expected: FAIL - [test_nested_shadow_element_click[outer_element\]] expected: FAIL [test_nested_shadow_element_click[inner_element\]] expected: FAIL - - [test_nested_shadow_element_click[checkbox\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini index 26b3aaa641b..5e4543ef0e9 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini @@ -1,7 +1,4 @@ [events.py] - [test_file_upload] - expected: FAIL - [test_form_control_send_text[input\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini index 4fd4b29e87f..40a4a701288 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini @@ -1,50 +1,19 @@ [file_upload.py] - expected: TIMEOUT [test_empty_text] expected: FAIL - [test_multiple_files] - expected: FAIL - [test_multiple_files_last_path_not_found] expected: FAIL - [test_multiple_files_without_multiple_attribute] - expected: FAIL - [test_multiple_files_send_twice] expected: FAIL [test_multiple_files_reset_with_element_clear] expected: FAIL - [test_single_file] - expected: FAIL - - [test_single_file_replaces_without_multiple_attribute] - expected: FAIL - [test_single_file_appends_with_multiple_attribute] expected: FAIL - [test_transparent] - expected: FAIL - - [test_obscured] - expected: FAIL - - [test_outside_viewport] - expected: FAIL - - [test_hidden] - expected: FAIL - - [test_display_none] - expected: FAIL - - [test_not_focused] - expected: FAIL - [test_focused] expected: ERROR 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 10a5a86e3d2..9dca7adc465 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 @@ -7,9 +7,3 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini index 6bcbe1197f6..72a20a6f7cf 100644 --- a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini @@ -1,2 +1,78 @@ [arguments.py] - expected: TIMEOUT + [test_no_such_element_with_unknown_id] + expected: FAIL + + [test_no_such_element_from_other_window_handle[open\]] + expected: FAIL + + [test_no_such_element_from_other_window_handle[closed\]] + expected: FAIL + + [test_no_such_element_from_other_frame[open\]] + expected: FAIL + + [test_no_such_element_from_other_frame[closed\]] + expected: FAIL + + [test_no_such_shadow_root_with_unknown_id] + expected: FAIL + + [test_no_such_shadow_root_from_other_window_handle[open\]] + expected: FAIL + + [test_no_such_shadow_root_from_other_window_handle[closed\]] + expected: FAIL + + [test_no_such_shadow_root_from_other_frame[open\]] + expected: FAIL + + [test_no_such_shadow_root_from_other_frame[closed\]] + expected: FAIL + + [test_stale_element_reference[top_context\]] + expected: FAIL + + [test_stale_element_reference[child_context\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[None-frame\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[None-window\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[False-frame\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[False-window\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[42-frame\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[42-window\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[value3-frame\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[value3-window\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[value4-frame\]] + expected: FAIL + + [test_invalid_argument_for_window_with_invalid_type[value4-window\]] + expected: FAIL + + [test_no_such_window_for_window_with_invalid_value] + expected: FAIL + + [test_element_reference[frame\]] + expected: FAIL + + [test_element_reference[shadow-root\]] + expected: FAIL + + [test_element_reference[window\]] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/execute_async.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/execute_async.py.ini index 6885d2e743e..26921d513c2 100644 --- a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/execute_async.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/execute_async.py.ini @@ -1,4 +1,5 @@ [execute_async.py] + expected: TIMEOUT [test_no_browsing_context] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini index 8818990c5ef..9c6615f080f 100644 --- a/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini @@ -1,5 +1,4 @@ [arguments.py] - expected: TIMEOUT [test_no_such_element_with_unknown_id] expected: FAIL @@ -78,9 +77,6 @@ [test_element_reference[frame\]] expected: FAIL - [test_element_reference[node\]] - expected: FAIL - [test_element_reference[shadow-root\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_script/execute.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_script/execute.py.ini index 8a1571d1d7b..ff13c80a5fe 100644 --- a/tests/wpt/meta/webdriver/tests/classic/execute_script/execute.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/execute_script/execute.py.ini @@ -1,4 +1,5 @@ [execute.py] + expected: TIMEOUT [test_no_browsing_context] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_element/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_element/find.py.ini index 7564f644b10..60f973b8a44 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_element/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_element/find.py.ini @@ -1,7 +1,6 @@ [find.py] - expected: TIMEOUT [test_no_browsing_context] - expected: ERROR + expected: FAIL [test_no_such_element_with_unknown_selector[not-existent\]] expected: FAIL @@ -15,18 +14,6 @@ [test_find_element[xpath-//a\]] expected: FAIL - [test_xhtml_namespace[css selector-#linkText\]] - expected: FAIL - - [test_xhtml_namespace[link text-full link text\]] - expected: FAIL - - [test_xhtml_namespace[partial link text-link text\]] - expected: FAIL - - [test_xhtml_namespace[tag name-a\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_element_from_shadow_root/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_element_from_shadow_root/find.py.ini index dba98c7726b..05e490d14fe 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_element_from_shadow_root/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_element_from_shadow_root/find.py.ini @@ -1,5 +1,4 @@ [find.py] - expected: TIMEOUT [test_null_parameter_value] expected: FAIL @@ -7,7 +6,7 @@ expected: FAIL [test_no_browsing_context] - expected: ERROR + expected: FAIL [test_no_such_shadow_root_with_element] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_elements/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_elements/find.py.ini index 44f232824bb..06a8b89b5b6 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_elements/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_elements/find.py.ini @@ -1,74 +1,22 @@ [find.py] - expected: TIMEOUT [test_no_browsing_context] - expected: ERROR - - [test_find_elements[css selector-#linkText\]] - expected: FAIL - - [test_find_elements[link text-full link text\]] - expected: FAIL - - [test_find_elements[partial link text-link text\]] - expected: FAIL - - [test_find_elements[tag name-a\]] expected: FAIL [test_find_elements[xpath-//a\]] expected: FAIL - [test_find_elements_link_text[<a href=#>link text</a>-link text\]] - expected: FAIL - - [test_find_elements_link_text[<a href=#> link text </a>-link text\]] - expected: FAIL - [test_find_elements_link_text[<a href=#>link<br>text</a>-link\\ntext\]] expected: FAIL - [test_find_elements_link_text[<a href=#>link&text</a>-link&text\]] - expected: FAIL - - [test_find_elements_link_text[<a href=#>LINK TEXT</a>-LINK TEXT\]] - expected: FAIL - [test_find_elements_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT\]] expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link text</a>-link\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#> partial link text </a>-link\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#>partial link text</a>-k t\]] - expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link<br>text</a>-k\\nt\]] expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link&text</a>-k&t\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#>PARTIAL LINK TEXT</a>-LINK\]] - expected: FAIL - [test_find_elements_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK\]] expected: FAIL - [test_xhtml_namespace[css selector-#linkText\]] - expected: FAIL - - [test_xhtml_namespace[link text-full link text\]] - expected: FAIL - - [test_xhtml_namespace[partial link text-link text\]] - expected: FAIL - - [test_xhtml_namespace[tag name-a\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_elements_from_element/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_elements_from_element/find.py.ini index 69ec1b4bbcc..47ac0c0b589 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_elements_from_element/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_elements_from_element/find.py.ini @@ -1,77 +1,28 @@ [find.py] - expected: TIMEOUT [test_no_browsing_context] - expected: ERROR - - [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_with_startnode_from_other_window_handle] + [test_no_such_element_with_shadow_root] expected: FAIL [test_no_such_element_with_startnode_from_other_frame] expected: FAIL - [test_stale_element_reference[top_context\]] - expected: FAIL - - [test_stale_element_reference[child_context\]] - expected: FAIL - [test_find_elements[xpath-//a\]] expected: FAIL - [test_find_elements_link_text[<a href=#>link text</a>-link text\]] - expected: FAIL - - [test_find_elements_link_text[<a href=#> link text </a>-link text\]] - expected: FAIL - [test_find_elements_link_text[<a href=#>link<br>text</a>-link\\ntext\]] expected: FAIL - [test_find_elements_link_text[<a href=#>link&text</a>-link&text\]] - expected: FAIL - - [test_find_elements_link_text[<a href=#>LINK TEXT</a>-LINK TEXT\]] - expected: FAIL - [test_find_elements_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT\]] expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link text</a>-link\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#> partial link text </a>-link\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#>partial link text</a>-k t\]] - expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link<br>text</a>-k\\nt\]] expected: FAIL - [test_find_elements_partial_link_text[<a href=#>partial link&text</a>-k&t\]] - expected: FAIL - - [test_find_elements_partial_link_text[<a href=#>PARTIAL LINK TEXT</a>-LINK\]] - expected: FAIL - [test_find_elements_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK\]] expected: FAIL - [test_xhtml_namespace[css selector-#linkText\]] - expected: FAIL - - [test_xhtml_namespace[link text-full link text\]] - expected: FAIL - - [test_xhtml_namespace[partial link text-link text\]] - expected: FAIL - - [test_xhtml_namespace[tag name-a\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_elements_from_shadow_root/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_elements_from_shadow_root/find.py.ini index 5328af1b701..18ed273c743 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_elements_from_shadow_root/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_elements_from_shadow_root/find.py.ini @@ -1,5 +1,4 @@ [find.py] - expected: TIMEOUT [test_null_parameter_value] expected: FAIL @@ -7,7 +6,7 @@ expected: FAIL [test_no_browsing_context] - expected: ERROR + expected: FAIL [test_no_such_shadow_root_with_element] 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 f00172fdc5a..44749396246 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 @@ -8,11 +8,5 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL - [test_computed_roles[<article>foo</article>-article-article\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini index 69b4a4c7d0b..c5bc0a36f6d 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini @@ -1,35 +1,13 @@ [get.py] - expected: TIMEOUT - [test_no_top_browsing_context] - expected: FAIL - [test_no_browsing_context] - expected: ERROR - - [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[open\]] + [test_no_such_element_with_shadow_root] expected: FAIL [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [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_normal] - expected: FAIL - [test_boolean_attribute[audio-attrs0\]] expected: FAIL @@ -86,9 +64,3 @@ [test_global_boolean_attributes] expected: FAIL - - [test_anchor_href[relative\]] - expected: FAIL - - [test_anchor_href[absolute\]] - 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 d55c5312a47..0af7750e50e 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 @@ -7,9 +7,3 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini index 646e2846e18..991123b881c 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini @@ -1,94 +1,12 @@ [get.py] - expected: TIMEOUT - [test_no_top_browsing_context] - expected: FAIL - [test_no_browsing_context] - expected: ERROR - - [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[open\]] + [test_no_such_element_with_shadow_root] expected: FAIL [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [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_property_non_existent] - expected: FAIL - - [test_content_attribute] - expected: FAIL - - [test_idl_attribute] - expected: FAIL - - [test_primitives["foobar"-foobar\]] - expected: FAIL - - [test_primitives[42-42\]] - expected: FAIL - - [test_primitives[js_primitive2-py_primitive2\]] - expected: FAIL - - [test_primitives[js_primitive3-py_primitive3\]] - expected: FAIL - - [test_primitives[null-None\]] - expected: FAIL - - [test_primitives[undefined-None\]] - expected: FAIL - - [test_collection_dom_token_list] - expected: FAIL - - [test_primitives_set_by_execute_script["foobar"-foobar\]] - expected: FAIL - - [test_primitives_set_by_execute_script[42-42\]] - expected: FAIL - - [test_primitives_set_by_execute_script[js_primitive2-py_primitive2\]] - expected: FAIL - - [test_primitives_set_by_execute_script[js_primitive3-py_primitive3\]] - expected: FAIL - - [test_primitives_set_by_execute_script[null-None\]] - expected: FAIL - - [test_primitives_set_by_execute_script[undefined-None\]] - expected: FAIL - - [test_web_reference[frame-WebFrame\]] - expected: FAIL - [test_web_reference[shadowRoot-ShadowRoot\]] expected: FAIL - - [test_web_reference[window-WebWindow\]] - expected: FAIL - - [test_mutated_element] - expected: FAIL - - [test_anchor_href[relative\]] - expected: FAIL - - [test_anchor_href[absolute\]] - 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 67875a58cd9..10339e7291b 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 @@ -8,11 +8,5 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - 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 0ac8ff98d59..879854dfc56 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 @@ -8,11 +8,5 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - 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 ad870f8f49b..66e31b2d5a7 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 @@ -8,12 +8,6 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL - [test_transform_capitalize[space\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini index 1f97f812861..9f75dbb4f9e 100644 --- a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini @@ -1,2 +1,18 @@ [enabled.py] - expected: TIMEOUT + [test_no_browsing_context] + expected: FAIL + + [test_no_such_element_with_shadow_root] + expected: FAIL + + [test_no_such_element_from_other_window_handle[closed\]] + expected: FAIL + + [test_stale_element_reference[child_context\]] + expected: FAIL + + [test_option_with_select[disabled\]] + expected: FAIL + + [test_optgroup_with_select[disabled\]] + 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 eb4c0299197..2c5777abee2 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 @@ -8,8 +8,5 @@ [test_no_such_element_from_other_window_handle[closed\]] expected: FAIL - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] + [test_stale_element_reference[child_context\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/new_session/unhandled_prompt_behavior.py.ini b/tests/wpt/meta/webdriver/tests/classic/new_session/unhandled_prompt_behavior.py.ini index ff2e1c72126..7ea404e4f6a 100644 --- a/tests/wpt/meta/webdriver/tests/classic/new_session/unhandled_prompt_behavior.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/new_session/unhandled_prompt_behavior.py.ini @@ -1,4 +1,5 @@ [unhandled_prompt_behavior.py] + expected: TIMEOUT [test_unhandled_prompt_behavior_as_object_default[handler0-expected_capability0-True-True\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini index 0a9efbca289..42ceab66336 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini @@ -9,16 +9,19 @@ expected: FAIL [test_backspace_erases_keys] - expected: FAIL + expected: ERROR [test_element_in_shadow_tree[outer-open\]] - expected: FAIL + expected: ERROR [test_element_in_shadow_tree[outer-closed\]] - expected: FAIL + expected: ERROR [test_element_in_shadow_tree[inner-open\]] - expected: FAIL + expected: ERROR [test_element_in_shadow_tree[inner-closed\]] - expected: FAIL + expected: ERROR + + [test_element_not_focused] + expected: ERROR diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_events.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_events.py.ini index 6dabfbb793f..ab545d924ac 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_events.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_events.py.ini @@ -1,273 +1,12 @@ [key_events.py] - [test_modifier_key_sends_correct_events[\\ue00a-ALT\]] - expected: FAIL - - [test_modifier_key_sends_correct_events[\\ue009-CONTROL\]] - expected: FAIL - - [test_modifier_key_sends_correct_events[\\ue03d-META\]] - expected: FAIL - [test_modifier_key_sends_correct_events[\\ue008-SHIFT\]] expected: FAIL - [test_modifier_key_sends_correct_events[\\ue052-R_ALT\]] - expected: FAIL - - [test_modifier_key_sends_correct_events[\\ue051-R_CONTROL\]] - expected: FAIL - - [test_modifier_key_sends_correct_events[\\ue053-R_META\]] - expected: FAIL - - [test_modifier_key_sends_correct_events[\\ue050-R_SHIFT\]] - expected: FAIL - [test_non_printable_key_sends_events[\\ue00c-ESCAPE\]] expected: FAIL - [test_non_printable_key_sends_events[\\ue014-RIGHT\]] - expected: FAIL - - [test_printable_key_sends_correct_events[a-KeyA0\]] - expected: FAIL - - [test_printable_key_sends_correct_events[a-KeyA1\]] - expected: FAIL - - [test_printable_key_sends_correct_events["-Quote\]] - expected: FAIL - - [test_printable_key_sends_correct_events[,-Comma\]] - expected: FAIL - - [test_printable_key_sends_correct_events[\\xe0-\]] - expected: FAIL - - [test_printable_key_sends_correct_events[\\u0416-\]] - expected: FAIL - - [test_printable_key_sends_correct_events[@-Digit2\]] - expected: FAIL - - [test_printable_key_sends_correct_events[\\u2603-\]] - expected: FAIL - - [test_printable_key_sends_correct_events[\\uf6c2-\]] - expected: FAIL - - [test_sequence_of_keydown_printable_keys_sends_events] - expected: FAIL - - [test_sequence_of_keydown_printable_characters_sends_events] - expected: FAIL - - [test_special_key_sends_keydown[ADD-expected0\]] - expected: FAIL - - [test_special_key_sends_keydown[ALT-expected1\]] - expected: FAIL - - [test_special_key_sends_keydown[BACKSPACE-expected2\]] - expected: FAIL - - [test_special_key_sends_keydown[CANCEL-expected3\]] - expected: FAIL - - [test_special_key_sends_keydown[CLEAR-expected4\]] - expected: FAIL - - [test_special_key_sends_keydown[CONTROL-expected5\]] - expected: FAIL - - [test_special_key_sends_keydown[DECIMAL-expected6\]] - expected: FAIL - - [test_special_key_sends_keydown[DELETE-expected7\]] - expected: FAIL - - [test_special_key_sends_keydown[DIVIDE-expected8\]] - expected: FAIL - - [test_special_key_sends_keydown[DOWN-expected9\]] - expected: FAIL - - [test_special_key_sends_keydown[END-expected10\]] - expected: FAIL - - [test_special_key_sends_keydown[ENTER-expected11\]] - expected: FAIL - [test_special_key_sends_keydown[EQUALS-expected12\]] expected: FAIL - [test_special_key_sends_keydown[ESCAPE-expected13\]] - expected: FAIL - - [test_special_key_sends_keydown[F1-expected14\]] - expected: FAIL - - [test_special_key_sends_keydown[F10-expected15\]] - expected: FAIL - - [test_special_key_sends_keydown[F11-expected16\]] - expected: FAIL - - [test_special_key_sends_keydown[F12-expected17\]] - expected: FAIL - - [test_special_key_sends_keydown[F2-expected18\]] - expected: FAIL - - [test_special_key_sends_keydown[F3-expected19\]] - expected: FAIL - - [test_special_key_sends_keydown[F4-expected20\]] - expected: FAIL - - [test_special_key_sends_keydown[F5-expected21\]] - expected: FAIL - - [test_special_key_sends_keydown[F6-expected22\]] - expected: FAIL - - [test_special_key_sends_keydown[F7-expected23\]] - expected: FAIL - - [test_special_key_sends_keydown[F8-expected24\]] - expected: FAIL - - [test_special_key_sends_keydown[F9-expected25\]] - expected: FAIL - - [test_special_key_sends_keydown[HELP-expected26\]] - expected: FAIL - - [test_special_key_sends_keydown[HOME-expected27\]] - expected: FAIL - - [test_special_key_sends_keydown[INSERT-expected28\]] - expected: FAIL - - [test_special_key_sends_keydown[LEFT-expected29\]] - expected: FAIL - - [test_special_key_sends_keydown[META-expected30\]] - expected: FAIL - - [test_special_key_sends_keydown[MULTIPLY-expected31\]] - expected: FAIL - - [test_special_key_sends_keydown[NULL-expected32\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD0-expected33\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD1-expected34\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD2-expected35\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD3-expected36\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD4-expected37\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD5-expected38\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD6-expected39\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD7-expected40\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD8-expected41\]] - expected: FAIL - - [test_special_key_sends_keydown[NUMPAD9-expected42\]] - expected: FAIL - - [test_special_key_sends_keydown[PAGE_DOWN-expected43\]] - expected: FAIL - - [test_special_key_sends_keydown[PAGE_UP-expected44\]] - expected: FAIL - [test_special_key_sends_keydown[PAUSE-expected45\]] expected: FAIL - - [test_special_key_sends_keydown[RETURN-expected46\]] - expected: FAIL - - [test_special_key_sends_keydown[RIGHT-expected47\]] - expected: FAIL - - [test_special_key_sends_keydown[R_ALT-expected48\]] - expected: FAIL - - [test_special_key_sends_keydown[R_ARROWDOWN-expected49\]] - expected: FAIL - - [test_special_key_sends_keydown[R_ARROWLEFT-expected50\]] - expected: FAIL - - [test_special_key_sends_keydown[R_ARROWRIGHT-expected51\]] - expected: FAIL - - [test_special_key_sends_keydown[R_ARROWUP-expected52\]] - expected: FAIL - - [test_special_key_sends_keydown[R_CONTROL-expected53\]] - expected: FAIL - - [test_special_key_sends_keydown[R_DELETE-expected54\]] - expected: FAIL - - [test_special_key_sends_keydown[R_END-expected55\]] - expected: FAIL - - [test_special_key_sends_keydown[R_HOME-expected56\]] - expected: FAIL - - [test_special_key_sends_keydown[R_INSERT-expected57\]] - expected: FAIL - - [test_special_key_sends_keydown[R_META-expected58\]] - expected: FAIL - - [test_special_key_sends_keydown[R_PAGEDOWN-expected59\]] - expected: FAIL - - [test_special_key_sends_keydown[R_PAGEUP-expected60\]] - expected: FAIL - - [test_special_key_sends_keydown[R_SHIFT-expected61\]] - expected: FAIL - - [test_special_key_sends_keydown[SEMICOLON-expected62\]] - expected: FAIL - - [test_special_key_sends_keydown[SEPARATOR-expected63\]] - expected: FAIL - - [test_special_key_sends_keydown[SHIFT-expected64\]] - expected: FAIL - - [test_special_key_sends_keydown[SPACE-expected65\]] - expected: FAIL - - [test_special_key_sends_keydown[SUBTRACT-expected66\]] - expected: FAIL - - [test_special_key_sends_keydown[TAB-expected67\]] - expected: FAIL - - [test_special_key_sends_keydown[UP-expected68\]] - expected: FAIL - - [test_special_key_sends_keydown[ZENKAKUHANKAKU-expected69\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_modifiers.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_modifiers.py.ini index 70b4b687388..118e70b33a8 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_modifiers.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_modifiers.py.ini @@ -1,10 +1,4 @@ [key_modifiers.py] - [test_shift_modifier_and_non_printable_keys[\\ue008\]] - expected: FAIL - - [test_shift_modifier_and_non_printable_keys[\\ue050\]] - expected: FAIL - [test_shift_modifier_generates_capital_letters[\\ue008\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_shortcuts.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_shortcuts.py.ini index 43e9ac6cf32..8a5f8770474 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_shortcuts.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_shortcuts.py.ini @@ -1,3 +1,6 @@ [key_shortcuts.py] [test_mod_a_mod_c_right_mod_v_pastes_text] expected: FAIL + + [test_mod_a_mod_x_deletes_all_text] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_special_keys.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_special_keys.py.ini index 9f97050ec49..5e1b1b41869 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_special_keys.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key_special_keys.py.ini @@ -1,7 +1,4 @@ [key_special_keys.py] - [test_codepoint_keys_behave_correctly[\\U0001f604\]] - expected: FAIL - [test_codepoint_keys_behave_correctly[\\U0001f60d\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/navigation.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/navigation.py.ini index 38af76d3cf4..b7b8bf52a22 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/navigation.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/navigation.py.ini @@ -1,4 +1,5 @@ [navigation.py] + expected: TIMEOUT [test_key] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_contextmenu.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_contextmenu.py.ini index e0fb2381634..62af3a877f5 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_contextmenu.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_contextmenu.py.ini @@ -1,9 +1,9 @@ [pointer_contextmenu.py] [test_control_click[\\ue009-ctrlKey\]] - expected: ERROR + expected: FAIL [test_control_click[\\ue051-ctrlKey\]] - expected: ERROR + expected: FAIL [test_release_control_click] - expected: ERROR + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_dblclick.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_dblclick.py.ini deleted file mode 100644 index 523d8d29edb..00000000000 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_dblclick.py.ini +++ /dev/null @@ -1,9 +0,0 @@ -[pointer_dblclick.py] - [test_dblclick_at_coordinates[0\]] - expected: FAIL - - [test_dblclick_at_coordinates[200\]] - expected: FAIL - - [test_no_dblclick_when_mouse_moves] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_modifier_click.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_modifier_click.py.ini index ebb9ef4dcc0..af13d756701 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_modifier_click.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_modifier_click.py.ini @@ -1,21 +1,21 @@ [pointer_modifier_click.py] [test_modifier_click[\\ue00a-altKey\]] - expected: ERROR + expected: FAIL [test_modifier_click[\\ue052-altKey\]] - expected: ERROR + expected: FAIL [test_modifier_click[\\ue03d-metaKey\]] - expected: ERROR + expected: FAIL [test_modifier_click[\\ue053-metaKey\]] - expected: ERROR + expected: FAIL [test_modifier_click[\\ue008-shiftKey\]] - expected: ERROR + expected: FAIL [test_modifier_click[\\ue050-shiftKey\]] - expected: ERROR + expected: FAIL [test_many_modifiers_click] - expected: ERROR + 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 4222966b349..d4ef4398b7f 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,4 +1,5 @@ [pointer_mouse.py] + expected: TIMEOUT [test_no_top_browsing_context] 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 5c08076b7b2..d7922cb4283 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 @@ -1,4 +1,5 @@ [pointer_pen.py] + expected: TIMEOUT [test_no_top_browsing_context] 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 2dd2ee19891..85e34998125 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 @@ -1,4 +1,5 @@ [pointer_touch.py] + expected: TIMEOUT [test_no_top_browsing_context] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence_tentative.py.ini b/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence_tentative.py.ini index aed5f673813..9c048ff9b5f 100644 --- a/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence_tentative.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence_tentative.py.ini @@ -1,4 +1,5 @@ [sequence_tentative.py] + expected: TIMEOUT [test_release_mouse_sequence_resets_dblclick_state[with release actions\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/set_window_rect/set.py.ini b/tests/wpt/meta/webdriver/tests/classic/set_window_rect/set.py.ini index 6b28c2efdf8..d530b687213 100644 --- a/tests/wpt/meta/webdriver/tests/classic/set_window_rect/set.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/set_window_rect/set.py.ini @@ -15,7 +15,7 @@ expected: FAIL [test_set_to_available_size] - expected: ERROR + expected: FAIL [test_set_smaller_than_minimum_browser_size] expected: FAIL @@ -30,10 +30,22 @@ expected: FAIL [test_negative_x_y] - expected: ERROR + expected: FAIL [test_set_to_screen_size] - expected: ERROR + expected: FAIL [test_set_larger_than_screen_size] - expected: ERROR + expected: FAIL + + [test_width_height_floats] + expected: FAIL + + [test_height_width_as_current] + expected: FAIL + + [test_height_as_current] + expected: FAIL + + [test_width_as_current] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini index ee73fbf4ce8..66625728565 100644 --- a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini @@ -16,6 +16,3 @@ [test_frame_id_shadow_root] expected: FAIL - - [test_frame_id_null] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_parent_frame/switch.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_parent_frame/switch.py.ini index ffd3d06f212..352421f84c1 100644 --- a/tests/wpt/meta/webdriver/tests/classic/switch_to_parent_frame/switch.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_parent_frame/switch.py.ini @@ -1,6 +1,3 @@ [switch.py] - [test_switch_from_iframe] - expected: FAIL - [test_switch_from_top_level] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_window/alerts.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_window/alerts.py.ini index 3e6ad0c8af9..aa34b0b2489 100644 --- a/tests/wpt/meta/webdriver/tests/classic/switch_to_window/alerts.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_window/alerts.py.ini @@ -1,3 +1,4 @@ [alerts.py] + expected: TIMEOUT [test_retain_tab_modal_status] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_window/switch.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_window/switch.py.ini index 9b0ec38199b..44ac97a7a36 100644 --- a/tests/wpt/meta/webdriver/tests/classic/switch_to_window/switch.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_window/switch.py.ini @@ -1,4 +1,5 @@ [switch.py] + expected: TIMEOUT [test_no_top_browsing_context] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/iframe.py.ini b/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/iframe.py.ini index dd77eca9d72..c6374102e3f 100644 --- a/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/iframe.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/take_element_screenshot/iframe.py.ini @@ -1,9 +1,3 @@ [iframe.py] [test_frame_element] expected: FAIL - - [test_source_origin[same_origin\]] - expected: FAIL - - [test_source_origin[cross_origin\]] - 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 new file mode 100644 index 00000000000..b63f4c9fb07 --- /dev/null +++ b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/iframe.py.ini @@ -0,0 +1,9 @@ +[iframe.py] + [test_always_captures_top_browsing_context] + expected: FAIL + + [test_source_origin[same_origin\]] + expected: FAIL + + [test_source_origin[cross_origin\]] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini index f2fac7a7fa1..aef7c9d5ddc 100644 --- a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini @@ -4,3 +4,6 @@ [test_no_browsing_context] expected: FAIL + + [test_format_and_dimensions] + expected: FAIL diff --git a/tests/wpt/meta/websockets/stream/tentative/write.any.js.ini b/tests/wpt/meta/websockets/stream/tentative/write.any.js.ini new file mode 100644 index 00000000000..491b41e2c47 --- /dev/null +++ b/tests/wpt/meta/websockets/stream/tentative/write.any.js.ini @@ -0,0 +1,118 @@ +[write.any.sharedworker.html?wpt_flags=h2] + expected: ERROR + +[write.any.serviceworker.html?default] + expected: ERROR + +[write.any.worker.html?wpt_flags=h2] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL + + +[write.any.sharedworker.html?wss] + expected: ERROR + +[write.any.html?default] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL + + +[write.any.worker.html?wss] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL + + +[write.any.serviceworker.html?wpt_flags=h2] + expected: ERROR + +[write.any.html?wpt_flags=h2] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL + + +[write.any.serviceworker.html?wss] + expected: ERROR + +[write.any.sharedworker.html?default] + expected: ERROR + +[write.any.worker.html?default] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL + + +[write.any.html?wss] + [a write that was incomplete at close time should reject] + expected: FAIL + + [garbage collection after close with a pending write promise should not crash] + expected: FAIL + + [writing a value that cannot be stringified should cause a rejection] + expected: FAIL + + [writing a resizable ArrayBuffer should be rejected] + expected: FAIL + + [writing a view on a shared buffer should be rejected] + expected: FAIL diff --git a/tests/wpt/meta/workers/constructors/Worker/Worker-constructor.html.ini b/tests/wpt/meta/workers/constructors/Worker/Worker-constructor.html.ini new file mode 100644 index 00000000000..80f9a4f15b8 --- /dev/null +++ b/tests/wpt/meta/workers/constructors/Worker/Worker-constructor.html.ini @@ -0,0 +1,2 @@ +[Worker-constructor.html] + expected: ERROR diff --git a/tests/wpt/meta/workers/tentative/SharedWorker-extendedLifetime.html.ini b/tests/wpt/meta/workers/tentative/SharedWorker-extendedLifetime.html.ini new file mode 100644 index 00000000000..086935d2b6d --- /dev/null +++ b/tests/wpt/meta/workers/tentative/SharedWorker-extendedLifetime.html.ini @@ -0,0 +1,3 @@ +[SharedWorker-extendedLifetime.html] + [SharedWorker lifetime should be extended with extendedLifetime] + expected: FAIL diff --git a/tests/wpt/meta/xhr/abort-during-done.window.js.ini b/tests/wpt/meta/xhr/abort-during-done.window.js.ini deleted file mode 100644 index cfce26bf75b..00000000000 --- a/tests/wpt/meta/xhr/abort-during-done.window.js.ini +++ /dev/null @@ -1,9 +0,0 @@ -[abort-during-done.window.html] - [XMLHttpRequest: abort() during DONE (sync)] - expected: FAIL - - [XMLHttpRequest: abort() during DONE (sync aborted in readystatechange)] - expected: FAIL - - [XMLHttpRequest: abort() during DONE (async)] - expected: FAIL diff --git a/tests/wpt/meta/xhr/abort-during-headers-received.window.js.ini b/tests/wpt/meta/xhr/abort-during-headers-received.window.js.ini deleted file mode 100644 index aa78b3966cc..00000000000 --- a/tests/wpt/meta/xhr/abort-during-headers-received.window.js.ini +++ /dev/null @@ -1,3 +0,0 @@ -[abort-during-headers-received.window.html] - [XMLHttpRequest: abort() during HEADERS_RECEIVED] - expected: FAIL diff --git a/tests/wpt/meta/xhr/abort-during-loading.window.js.ini b/tests/wpt/meta/xhr/abort-during-loading.window.js.ini deleted file mode 100644 index 33a6772164b..00000000000 --- a/tests/wpt/meta/xhr/abort-during-loading.window.js.ini +++ /dev/null @@ -1,3 +0,0 @@ -[abort-during-loading.window.html] - [XMLHttpRequest: abort() during LOADING] - expected: FAIL diff --git a/tests/wpt/tests/client-hints/permissions-policy/WEB_FEATURES.yml b/tests/wpt/tests/client-hints/permissions-policy/WEB_FEATURES.yml new file mode 100644 index 00000000000..da7599308cc --- /dev/null +++ b/tests/wpt/tests/client-hints/permissions-policy/WEB_FEATURES.yml @@ -0,0 +1,6 @@ +features: +- name: ua-client-hints + # Note: if any permissions-policy tests are added that do not + # depend on ua-client-hints, `files` below should be updated + # accordingly. + files: "**" diff --git a/tests/wpt/tests/container-timing/resources/container-timing-helpers.js b/tests/wpt/tests/container-timing/resources/container-timing-helpers.js index a80ad964fef..8b3f21dff56 100644 --- a/tests/wpt/tests/container-timing/resources/container-timing-helpers.js +++ b/tests/wpt/tests/container-timing/resources/container-timing-helpers.js @@ -20,3 +20,19 @@ function checkContainerEntry(entry, identifier, last_element_id, beforeRender) { function checkContainerSize(entry, size) { assert_equals(entry.size, size); } + +function finishOnElementTiming(t) { + const finish_observer = new PerformanceObserver(() => { + requestAnimationFrame(() => { t.done(); }); + }); + finish_observer.observe({ entryTypes: ['element'] }); +} + +function addPaintingElementTimingAfterDoubleRAF(parent) { + requestAnimationFrame(() => requestAnimationFrame(() => { + const finish_img = document.createElement('img'); + finish_img.src = '/container-timing/resources/square100.png'; + finish_img.setAttribute('elementtiming', ''); + parent.appendChild(finish_img); + })); +} diff --git a/tests/wpt/tests/container-timing/tentative/containertiming-with-child-ignore-and-child-img.html b/tests/wpt/tests/container-timing/tentative/containertiming-with-child-ignore-and-child-img.html new file mode 100644 index 00000000000..b4fa9754c10 --- /dev/null +++ b/tests/wpt/tests/container-timing/tentative/containertiming-with-child-ignore-and-child-img.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Container Timing: an image inside a containertiming-ignore inside a containertiming root</title> +<body> +<style> +body { + margin: 0; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/container-timing/resources/container-timing-helpers.js"></script> +<script src="/element-timing/resources/element-timing-helpers.js"></script> +<script> + async_test(function (t) { + assert_implements(window.PerformanceContainerTiming, "PerformanceContainerTiming is not implemented"); + const observer = new PerformanceObserver( + function(entryList) { + assert_unreached("No entry is expected with nothing to paint"); + } + ); + observer.observe({entryTypes: ['container']}); + + finishOnElementTiming(t); + + // Add a div that is the container timing root + const div1 = document.createElement('div'); + div1.setAttribute('containertiming', 'div1_ct'); + document.body.appendChild(div1); + + // Intermediate ignore should block paint events + const div2 = document.createElement('div'); + div2.setAttribute('containertiming-ignore', ''); + div1.appendChild(div2) + + // Add image of width equal to 100 and height equal to 100. + const img = document.createElement('img'); + img.src = '/container-timing/resources/square100.png'; + img.setAttribute('id', 'img_id'); + div2.appendChild(img); + + addPaintingElementTimingAfterDoubleRAF(document.body); + }, 'Paint of the image child of container timing with ignore in the middle is not reported.'); +</script> + +</body> diff --git a/tests/wpt/tests/container-timing/tentative/containertiming-with-ignore-and-child-img.html b/tests/wpt/tests/container-timing/tentative/containertiming-with-ignore-and-child-img.html new file mode 100644 index 00000000000..20e9e4a9218 --- /dev/null +++ b/tests/wpt/tests/container-timing/tentative/containertiming-with-ignore-and-child-img.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Container Timing: observe with a node with containertiming and containertiming-ignore, and an image child</title> +<body> +<style> +body { + margin: 0; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/container-timing/resources/container-timing-helpers.js"></script> +<script src="/element-timing/resources/element-timing-helpers.js"></script> +<script> + let beforeRender; + async_test(function (t) { + assert_implements(window.PerformanceContainerTiming, "PerformanceContainerTiming is not implemented"); + const observer = new PerformanceObserver( + t.step_func_done(function(entryList) { + assert_equals(entryList.getEntries().length, 1); + const entry = entryList.getEntries()[0]; + checkContainerEntry(entry, 'div_ct', 'img_id', beforeRender) + checkRect(entry, [0, 100, 0, 100]) + checkContainerSize(entry, 10000); + }) + ); + observer.observe({entryTypes: ['container']}); + + // Add a div that is the container timing root + // and containertiming-ignore, that should be ignored as + // containertiming takes precedence. + const div = document.createElement('div'); + div.setAttribute('containertiming', 'div_ct'); + div.setAttribute('containertiming-ignore', ''); + document.body.appendChild(div); + // Add image of width equal to 100 and height equal to 100. + const img = document.createElement('img'); + img.src = '/container-timing/resources/square100.png'; + img.setAttribute('id', 'img_id'); + div.appendChild(img); + beforeRender = performance.now(); + }, 'Paint of the image child of container timing with ignore is not blocked.'); +</script> + +</body> diff --git a/tests/wpt/tests/container-timing/tentative/ignore-with-containertiming-and-child-img.html b/tests/wpt/tests/container-timing/tentative/ignore-with-containertiming-and-child-img.html new file mode 100644 index 00000000000..841b4441d4d --- /dev/null +++ b/tests/wpt/tests/container-timing/tentative/ignore-with-containertiming-and-child-img.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Container Timing: an image inside a containertiming inside a containertiming-ignore</title> +<body> +<style> +body { + margin: 0; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/container-timing/resources/container-timing-helpers.js"></script> +<script src="/element-timing/resources/element-timing-helpers.js"></script> +<script> + let beforeRender; + async_test(function (t) { + assert_implements(window.PerformanceContainerTiming, "PerformanceContainerTiming is not implemented"); + const observer = new PerformanceObserver( + t.step_func_done(function(entryList) { + assert_equals(entryList.getEntries().length, 1); + const entry = entryList.getEntries()[0]; + checkContainerEntry(entry, 'div2_ct', 'img_id', beforeRender) + checkRect(entry, [0, 100, 0, 100]) + checkContainerSize(entry, 10000); + }) + ); + observer.observe({entryTypes: ['container']}); + + // Add a div that is the container timing root + const div1 = document.createElement('div'); + div1.setAttribute('containertiming-ignore', ''); + document.body.appendChild(div1); + + // Intermediate ignore should block paint events + const div2 = document.createElement('div'); + div2.setAttribute('containertiming', 'div2_ct'); + div1.appendChild(div2) + + // Add image of width equal to 100 and height equal to 100. + const img = document.createElement('img'); + img.src = '/container-timing/resources/square100.png'; + img.setAttribute('id', 'img_id'); + div2.appendChild(img); + + beforeRender = performance.now(); +}, 'An image inside a containertiming, inside a containertiming-ignore is still reported.'); +</script> + +</body> diff --git a/tests/wpt/tests/content-security-policy/default-src/default-src-sri_hash.sub.html b/tests/wpt/tests/content-security-policy/default-src/default-src-sri_hash.sub.html index 87fce5961fd..87389c306a5 100644 --- a/tests/wpt/tests/content-security-policy/default-src/default-src-sri_hash.sub.html +++ b/tests/wpt/tests/content-security-policy/default-src/default-src-sri_hash.sub.html @@ -7,6 +7,9 @@ <script src='/resources/testharnessreport.js' nonce='dummy'></script> <!-- CSP served: default-src {{domains[www]}}:* 'nonce-dummy' 'sha256-wIc3KtqOuTFEu6t17sIBuOswgkV406VJvhSk79Gw6U0=' 'ShA256-L7/UQ9VWpyG7C9RDEC4ctS5hI3Zcw+ta+haPGlByG9c=' 'sha512-rYCVMxWV5nq8IsMo+UZNObWtEiWGok/vDN8BMoEQi41s0znSes6E1Q2aag3Lw3u2J1w2rqH7uF2ws6FpQhfSOA=='; style-src 'unsafe-inline' --> + <!-- The domain here is intentionally served with `www`. In the event that the integrity check fails, + the request should be disallowed by the source list. If we were to use {{domains[]}}, + then we would not be able to observe the difference with regards to the integrity check --> <!-- ShA256 is intentionally mixed case --> </head> @@ -18,6 +21,8 @@ var port = "{{ports[http][0]}}"; if (location.protocol === "https:") port = "{{ports[https][0]}}"; + // Since {{domains[www]}} is allowed by the CSP policy, regardless of the integrity check + // the request would be allowed. var crossorigin_base = location.protocol + "//{{domains[www]}}:" + port; // Test name, src, integrity, expected to run. diff --git a/tests/wpt/tests/content-security-policy/script-src/script-src-sri_hash.sub.html b/tests/wpt/tests/content-security-policy/script-src/script-src-sri_hash.sub.html index 9216e2b0d49..e290911183d 100644 --- a/tests/wpt/tests/content-security-policy/script-src/script-src-sri_hash.sub.html +++ b/tests/wpt/tests/content-security-policy/script-src/script-src-sri_hash.sub.html @@ -7,6 +7,9 @@ <script src='/resources/testharnessreport.js' nonce='dummy'></script> <!-- CSP served: script-src {{domains[www]}}:* 'nonce-dummy' 'sha256-wIc3KtqOuTFEu6t17sIBuOswgkV406VJvhSk79Gw6U0=' 'ShA256-L7/UQ9VWpyG7C9RDEC4ctS5hI3Zcw+ta+haPGlByG9c=' 'sha512-rYCVMxWV5nq8IsMo+UZNObWtEiWGok/vDN8BMoEQi41s0znSes6E1Q2aag3Lw3u2J1w2rqH7uF2ws6FpQhfSOA==' --> + <!-- The domain here is intentionally served with `www`. In the event that the integrity check fails, + the request should be disallowed by the source list. If we were to use {{domains[]}}, + then we would not be able to observe the difference with regards to the integrity check --> <!-- ShA256 is intentionally mixed case --> </head> @@ -18,6 +21,8 @@ var port = "{{ports[http][0]}}"; if (location.protocol === "https:") port = "{{ports[https][0]}}"; + // Since {{domains[www]}} is allowed by the CSP policy, regardless of the integrity check + // the request would be allowed. var crossorigin_base = location.protocol + "//{{domains[www]}}:" + port; // Test name, src, integrity, expected to run. diff --git a/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html b/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html index c5e33dc4253..9a8ad7a4ef2 100644 --- a/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html +++ b/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html @@ -2,11 +2,12 @@ <html> <head> - <title>Parser-inserted scripts without a correct nonce are not allowed with `strict-dynamic` in the script-src directive.</title> + <title>Parser-inserted scripts without a correct nonce are not allowed with `Strict-Dynamic` in the script-src directive.</title> <script src='/resources/testharness.js' nonce='dummy'></script> <script src='/resources/testharnessreport.js' nonce='dummy'></script> - <!-- CSP served: script-src 'strict-dynamic' 'nonce-dummy' --> + <!-- CSP served: script-src 'Strict-Dynamic' 'nonce-dummy' --> + <!-- Strict-Dynamic is intentionally mixed case --> </head> <body> diff --git a/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.headers b/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.headers index b7918c93323..9d0b3b93d44 100644 --- a/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.headers +++ b/tests/wpt/tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.headers @@ -2,4 +2,4 @@ Expires: Mon, 26 Jul 1997 05:00:00 GMT Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0, false Pragma: no-cache -Content-Security-Policy: script-src 'strict-dynamic' 'nonce-dummy' +Content-Security-Policy: script-src 'Strict-Dynamic' 'nonce-dummy' diff --git a/tests/wpt/tests/cookie-store/META.yml b/tests/wpt/tests/cookie-store/META.yml index 68c30024552..4bbc6311bdc 100644 --- a/tests/wpt/tests/cookie-store/META.yml +++ b/tests/wpt/tests/cookie-store/META.yml @@ -1,4 +1,3 @@ spec: https://wicg.github.io/cookie-store/ suggested_reviewers: - - inexorabletash - - ayuishii + - dcthetall diff --git a/tests/wpt/tests/cookie-store/cookieStore_special_names.https.any.js b/tests/wpt/tests/cookie-store/cookieStore_special_names.https.any.js index e2a3df7fe33..1e12674a7f7 100644 --- a/tests/wpt/tests/cookie-store/cookieStore_special_names.https.any.js +++ b/tests/wpt/tests/cookie-store/cookieStore_special_names.https.any.js @@ -3,7 +3,7 @@ 'use strict'; -['__Secure-', '__Host-'].forEach(prefix => { +['__Secure-', '__secure-', '__Host-', '__host-'].forEach(prefix => { promise_test(async testCase => { await cookieStore.set(`${prefix}cookie-name`, `secure-cookie-value`); assert_equals( @@ -32,25 +32,27 @@ }, `cookieStore.delete with ${prefix} name on secure origin`); }); -promise_test(async testCase => { - const currentUrl = new URL(self.location.href); - const currentDomain = currentUrl.hostname; - await promise_rejects_js(testCase, TypeError, - cookieStore.set({ name: '__Host-cookie-name', value: 'cookie-value', - domain: currentDomain })); -}, 'cookieStore.set with __Host- prefix and a domain option'); +['__Host-', '__host-'].forEach(prefix => { + promise_test(async testCase => { + const currentUrl = new URL(self.location.href); + const currentDomain = currentUrl.hostname; + await promise_rejects_js(testCase, TypeError, + cookieStore.set({ name: `${prefix}cookie-name`, value: 'cookie-value', + domain: currentDomain })); + }, `cookieStore.set with ${prefix} prefix and a domain option`); -promise_test(async testCase => { - await cookieStore.set({ name: '__Host-cookie-name', value: 'cookie-value', - path: "/" }); + promise_test(async testCase => { + await cookieStore.set({ name: `${prefix}cookie-name`, value: 'cookie-value', + path: "/" }); - assert_equals( - (await cookieStore.get(`__Host-cookie-name`)).value, "cookie-value"); + assert_equals( + (await cookieStore.get(`${prefix}cookie-name`)).value, "cookie-value"); - await promise_rejects_js(testCase, TypeError, - cookieStore.set( { name: '__Host-cookie-name', value: 'cookie-value', - path: "/path" })); -}, 'cookieStore.set with __Host- prefix a path option'); + await promise_rejects_js(testCase, TypeError, + cookieStore.set( { name: `${prefix}cookie-name`, value: 'cookie-value', + path: "/path" })); + }, `cookieStore.set with ${prefix} prefix a path option`); +}); promise_test(async testCase => { let exceptionThrown = false; diff --git a/tests/wpt/tests/cookie-store/encoding.https.any.js b/tests/wpt/tests/cookie-store/encoding.https.any.js index 941639bdaec..f5d2ca15e71 100644 --- a/tests/wpt/tests/cookie-store/encoding.https.any.js +++ b/tests/wpt/tests/cookie-store/encoding.https.any.js @@ -4,15 +4,21 @@ 'use strict'; -cookie_test(async t => { +promise_test(async t => { await setCookieStringHttp('\uFEFFcookie=value; path=/'); + t.add_cleanup(async () => { + await setCookieStringHttp('\uFEFFcookie=value; path=/; Max-Age=0'); + }); const cookie = await cookieStore.get('\uFEFFcookie'); assert_equals(cookie.name, '\uFEFFcookie'); assert_equals(cookie.value, 'value'); }, 'BOM not stripped from name'); -cookie_test(async t => { +promise_test(async t => { await setCookieStringHttp('cookie=\uFEFFvalue; path=/'); + t.add_cleanup(async () => { + await setCookieStringHttp('cookie=\uFEFFvalue; path=/; Max-Age=0'); + }); const cookie = await cookieStore.get('cookie'); assert_equals(cookie.name, 'cookie'); assert_equals(cookie.value, '\uFEFFvalue'); diff --git a/tests/wpt/tests/cookie-store/httponly_cookies.https.window.js b/tests/wpt/tests/cookie-store/httponly_cookies.https.window.js index 605e94e6744..836f47da3f6 100644 --- a/tests/wpt/tests/cookie-store/httponly_cookies.https.window.js +++ b/tests/wpt/tests/cookie-store/httponly_cookies.https.window.js @@ -2,7 +2,7 @@ 'use strict'; -cookie_test(async t => { +promise_test(async t => { let eventPromise = observeNextCookieChangeEvent(); await setCookieStringHttp('HTTPONLY-cookie=value; path=/; httponly'); assert_equals( @@ -29,6 +29,9 @@ cookie_test(async t => { eventPromise = observeNextCookieChangeEvent(); await setCookieStringHttp( 'HTTPONLY-cookie=DELETED; path=/; max-age=0; httponly'); + t.add_cleanup(async () => { + await setCookieStringHttp(`HTTPONLY-cookie=DELETED; path=/; httponly; Max-Age=0`); + }); assert_equals( await getCookieString(), undefined, @@ -41,6 +44,9 @@ cookie_test(async t => { // HTTPONLY cookie changes should not have been observed; perform // a dummy change to verify that nothing else was queued up. await cookieStore.set('TEST', 'dummy'); + t.add_cleanup(async () => { + await cookieStore.delete('TEST'); + }); await verifyCookieChangeEvent( eventPromise, {changed: [{name: 'TEST', value: 'dummy'}]}, 'HttpOnly cookie deletion was not observed'); @@ -68,8 +74,11 @@ cookie_test(async t => { 'httpOnly is not an option for CookieStore.set()'); }, 'HttpOnly cookies can not be set by CookieStore'); -cookie_test(async t => { +promise_test(async t => { await setCookieStringHttp('HTTPONLY-cookie=value; path=/; httponly'); + t.add_cleanup(async () => { + await setCookieStringHttp(`HTTPONLY-cookie=DELETED; path=/; httponly; Max-Age=0`); + }); assert_equals( await getCookieString(), undefined, diff --git a/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js b/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js index 8e23ff2c422..82ca135f88e 100644 --- a/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js +++ b/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js @@ -210,10 +210,12 @@ async function cookie_test(func, description) { // Wipe cookies used by tests before and after the test. async function deleteAllCookies() { - await Promise.all((await cookieStore.getAll()).map(async ({name, value}) => { - await cookieStore.delete(name); - await cookieStore.delete({name: name, partitioned: true}); - })); + const cookies = await cookieStore.getAll(); + await Promise.all(cookies.flatMap( + ({name}) => + [cookieStore.delete(name), + cookieStore.delete({name, partitioned: true}), + ])); } return promise_test(async t => { diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html b/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html index 47cb3b8d86a..ffe3b45ba0d 100644 --- a/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html +++ b/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html @@ -11,7 +11,8 @@ .anchor-a { anchor-name: --a; } .anchor-b { anchor-name: --b; } - .anchor-a, .anchor-b { + .anchor-ab { anchor-name: --a, --b; } + .anchor-a, .anchor-b, .anchor-ab { background: skyblue; height: 10px; } @@ -159,7 +160,8 @@ <div class=anchor-b></div> <div class=anchor-a></div><!--A--> <div class=scope-a> - <div class=anchor-b></div><!--B--> + <div class=anchor-b></div> + <div class=anchor-ab></div><!--B--> <div class=anchor-a></div> </div> <div class=anchored-a></div> @@ -169,7 +171,7 @@ test((t) => { inflate(t, test_scope_a); assert_equals(getComputedStyle(main.querySelector('.anchored-a')).top, '20px'); - assert_equals(getComputedStyle(main.querySelector('.anchored-b')).top, '30px'); + assert_equals(getComputedStyle(main.querySelector('.anchored-b')).top, '40px'); }, 'anchor-scope:--a scopes only --a'); </script> @@ -177,8 +179,8 @@ <div class=anchor-b></div><!--B--> <div class=anchor-a></div> <div class=scope-b> - <div class=anchor-b></div> <div class=anchor-a></div><!--A--> + <div class=anchor-b></div> </div> <div class=anchored-a></div> <div class=anchored-b></div> @@ -186,7 +188,7 @@ <script> test((t) => { inflate(t, test_scope_b); - assert_equals(getComputedStyle(main.querySelector('.anchored-a')).top, '40px'); + assert_equals(getComputedStyle(main.querySelector('.anchored-a')).top, '30px'); assert_equals(getComputedStyle(main.querySelector('.anchored-b')).top, '10px'); }, 'anchor-scope:--b scopes only --b'); </script> diff --git a/tests/wpt/tests/css/css-anchor-position/chrome-420329041-crash.html b/tests/wpt/tests/css/css-anchor-position/chrome-420329041-crash.html new file mode 100644 index 00000000000..2b236a371e5 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/chrome-420329041-crash.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="help" href="https://crbug.com/420329041"> +<style> + #crash { + position: absolute; + left: anchor(right); + --svg: url("data:image/svg+xml,"); + content: var(--svg); + fill: var(--svg); + } +</style> +<p>Pass if no crash</p> +<div id="crash"></div> diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img-ref.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img-ref.html new file mode 100644 index 00000000000..565698f79ec --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img-ref.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<style> + .target { + width: 100px; + height: 100px; + border-radius: 25px; + box-sizing: border-box; + background-image: url("/images/green.png"); + corner-shape: notch superellipse(3) bevel scoop; + } +</style> +<div class=target></div> diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img.html new file mode 100644 index 00000000000..82662d25562 --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-img.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="match" href="corner-shape-img-ref.html"> +<meta name="fuzzy" content="maxDifference=0-64;totalPixels=0-100"> +<style> + img { + width: 100px; + height: 100px; + border-radius: 25px; + box-sizing: border-box; + corner-shape: notch superellipse(3) bevel scoop; + } +</style> +<img src="/images/green.png">
\ No newline at end of file diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html index 12cd2546bf4..2d4b56f831b 100644 --- a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html @@ -17,7 +17,7 @@ <meta name="variant" content="?corner-top-left-shape=superellipse(-4)&border-radius=40%"> <meta name="variant" content="?corner-top-left-shape=superellipse(2.5)&border-radius=20%&border-width=10px"> <meta name="variant" content="?corner-top-right-shape=scoop&border-radius=20%&border-width=10px"> -<meta name="variant" content="?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px&border-left-color=purple"> +<meta name="variant" content="?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px"> <meta name="variant" content="?corner-shape=superellipse(3)&border-radius=40px&box-shadow=10px 10px 0 10px black"> <meta name="variant" content="?border-radius=30%&corner-shape=superellipse(-1.5)&box-shadow=10px%2010px%200%2010px%20black"> <meta name="variant" content="?border-radius=40%&corner-shape=notch&box-shadow=10px%2010px%200%2010px%20yellow"> diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html index 5293589222a..4a0c575b3b7 100644 --- a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-precise.html @@ -19,13 +19,14 @@ <meta name="variant" content="?corner-top-left-shape=superellipse(-0.5)&border-radius=40px"> <meta name="variant" content="?corner-shape=squircle&border-top-left-radius=25%&border-width=10px"> <meta name="variant" content="?corner-bottom-left-shape=bevel&border-bottom-left-radius=30px"> -<meta name="variant" content="?corner-top-left-shape=bevel&border-width=10px&border-color=black"> -<meta name="variant" content="?corner-top-right-shape=bevel&border-width=10px&border-color=black"> +<meta name="variant" content="?corner-top-left-shape=bevel&border-width=10px"> +<meta name="variant" content="?corner-top-right-shape=bevel&border-width=10px"> <meta name="variant" content="?corner-bottom-left-shape=bevel&border-width=10px&border-radius=20px"> <meta name="variant" content="?corner-bottom-right-shape=bevel&border-width=10px&border-radius=20px"> <meta name="variant" content="?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel"> <meta name="variant" content="?border-top-left-radius=50%&corner-shape=superellipse(0.7)&border-left-width=30px&border-top-width=30px"> <meta name="variant" content="?border-radius=50%&corner-shape=bevel&box-shadow=10px%2010px%200%2010px%20black"> +<meta name="variant" content="?corner-shape=notch&border-radius=30px&border-width=30px"> <style> body { margin: 0; diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-shape.js b/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-shape.js index 4757a43ad05..c08a95c7d75 100644 --- a/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-shape.js +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-shape.js @@ -87,10 +87,6 @@ function add_corner(ctx, ax, ay, bx, by, curvature) { * 'border-top-right-radius': [number, number], * 'border-bottom-left-radius': [number, number], * 'border-bottom-right-radius': [number, number], - * 'border-top-color': string, - * 'border-right-color': string, - * 'border-left-color': string, - * 'border-bottom-color': string, * 'border-top-width': number, * 'border-right-width': number, * 'border-bottom-width': number, @@ -109,42 +105,8 @@ function render_rect_with_corner_shapes(style, ctx, width, height) { add_corner(ctx, ...params.outer_rect, params.shape); } - function draw_inner_corner_from_params(params) { - add_corner(ctx, ...params.inner_rect, params.shape); - } - function draw_inner_corner(corner) { - draw_inner_corner_from_params(corner_params[corner]); - } - - function draw_shadow() { - if (!style.shadow || !style.shadow.length) { - return; - } - - for (const {spread, offset, color} of style.shadow) { - const params = resolve_corner_params(style, width, height, spread); - ctx.save(); - ctx.translate(...offset); - ctx.beginPath(); - ctx.lineTo(params['top-right'].inner_rect[0], params['top-right'].inner_rect[1]); - draw_inner_corner_from_params(params['top-right']); - ctx.lineTo(params['top-right'].inner_rect[2], params['top-right'].inner_rect[3]) - ctx.lineTo(params['bottom-right'].inner_rect[0], params['bottom-right'].inner_rect[1]) - draw_inner_corner_from_params(params['bottom-right']); - ctx.lineTo(params['bottom-right'].inner_rect[2], params['bottom-right'].inner_rect[3]); - ctx.lineTo(params['bottom-left'].inner_rect[0], params['bottom-left'].inner_rect[1]); - draw_inner_corner_from_params(params['bottom-left']); - ctx.lineTo(params['bottom-left'].inner_rect[2], params['bottom-left'].inner_rect[3]) - ctx.lineTo(params['top-left'].inner_rect[0], params['top-left'].inner_rect[1]) - draw_inner_corner_from_params(params['top-left']); - ctx.lineTo(params['top-left'].inner_rect[2], params['top-left'].inner_rect[3]); - ctx.lineTo(params['top-right'].inner_rect[0], params['top-right'].inner_rect[1]); - ctx.fillStyle = color; - ctx.closePath(); - ctx.fill("nonzero"); - ctx.restore(); - } + add_corner(ctx, ...corner_params[corner].inner_rect, corner_params[corner].shape); } function draw_outer_path() { @@ -157,6 +119,15 @@ function render_rect_with_corner_shapes(style, ctx, width, height) { ctx.fill("nonzero"); } + for (const {spread, offset, color} of (style.shadow || [])) { + ctx.save(); + ctx.translate(offset[0] - spread, offset[1] - spread); + ctx.scale((width + spread * 2) / width, (height + spread * 2) / height); + ctx.fillStyle = color; + draw_outer_path(); + ctx.restore(); + } + const inner_rect = [ style["border-left-width"], style["border-top-width"], @@ -164,70 +135,8 @@ function render_rect_with_corner_shapes(style, ctx, width, height) { height - style["border-bottom-width"], ]; - draw_shadow(); - { - ctx.save(); - ctx.beginPath(); - ctx.moveTo(0, 0); - ctx.lineTo(corner_params['top-left'].inner_rect[2], corner_params['top-left'].inner_rect[1]) - ctx.lineTo(corner_params['top-left'].inner_rect[2], inner_rect[1]); - ctx.lineTo(corner_params['top-right'].inner_rect[0], inner_rect[1]); - ctx.lineTo(corner_params['top-right'].inner_rect[0], corner_params['top-right'].inner_rect[3]); - ctx.lineTo(width, 0); - ctx.closePath(); - ctx.clip(); - ctx.fillStyle = style['border-top-color']; - draw_outer_path(); - ctx.restore(); - } - - { - ctx.save(); - ctx.beginPath(); - ctx.moveTo(width, 0); - ctx.lineTo(corner_params['top-right'].inner_rect[0], corner_params['top-right'].inner_rect[3]); - ctx.lineTo(inner_rect[2], corner_params['top-right'].inner_rect[3]); - ctx.lineTo(inner_rect[2], corner_params['bottom-right'].inner_rect[1]); - ctx.lineTo(corner_params['bottom-right'].inner_rect[2], corner_params['bottom-right'].inner_rect[1]); - ctx.lineTo(width, height); - ctx.closePath(); - ctx.clip(); - ctx.fillStyle = style['border-right-color']; - draw_outer_path(); - ctx.restore(); - } - - { - ctx.save(); - ctx.beginPath(); - ctx.lineTo(width, height); - ctx.lineTo(corner_params['bottom-right'].inner_rect[2], corner_params['bottom-right'].inner_rect[1]); - ctx.lineTo(corner_params['bottom-right'].inner_rect[2], inner_rect[3]); - ctx.lineTo(corner_params['bottom-left'].inner_rect[0], inner_rect[3]); - ctx.lineTo(corner_params['bottom-left'].inner_rect[0], corner_params['bottom-left'].inner_rect[3]); - ctx.lineTo(0, height); - ctx.closePath(); - ctx.clip(); - ctx.fillStyle = style['border-bottom-color']; - draw_outer_path(); - ctx.restore(); - } - - { - ctx.save(); - ctx.beginPath(); - ctx.lineTo(0, height); - ctx.lineTo(corner_params['bottom-left'].inner_rect[0], corner_params['bottom-left'].inner_rect[3]); - ctx.lineTo(inner_rect[0], corner_params['bottom-left'].inner_rect[3]); - ctx.lineTo(inner_rect[0], corner_params['top-left'].inner_rect[1]); - ctx.lineTo(corner_params['top-left'].inner_rect[2], corner_params['top-left'].inner_rect[1]) - ctx.lineTo(0, 0); - ctx.closePath(); - ctx.clip(); - ctx.fillStyle = style['border-left-color']; - draw_outer_path(); - ctx.restore(); - } + ctx.fillStyle = "black"; + draw_outer_path(); ctx.save(); ctx.beginPath(); diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-utils.js b/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-utils.js index ad3b235addf..b6f329e8248 100644 --- a/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-utils.js +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/resources/corner-utils.js @@ -112,29 +112,11 @@ function resolve_corner_params(style, width, height, outset = null) { outer_rect[3] + inner_offset[3] * offset[0], ]; - let inner_shape = shape; - if (outset) { - const new_width = width + outset * 2; - const new_height = height + outset * 2; - inner_rect = [ - (outer_rect[0] / width) * new_width - outset, - (outer_rect[1] / height) * new_height - outset, - (outer_rect[2] / width) * new_width - outset, - (outer_rect[3] / height) * new_height - outset - ] - } else if (shape > 2 || shape < 0.5) { - const outer_length = Math.hypot( - outer_rect[2] - outer_rect[0], outer_rect[3] - outer_rect[1]); - const inner_length = Math.hypot( - inner_rect[2] - inner_rect[0], inner_rect[3] - inner_rect[1]) - } - return [ corner, { outer_rect, shape, - inner_shape, inset, inner_rect, inner_offset, diff --git a/tests/wpt/tests/css/css-color-hdr/parsing.html b/tests/wpt/tests/css/css-color-hdr/parsing.html index 2447891f2c4..688043039de 100644 --- a/tests/wpt/tests/css/css-color-hdr/parsing.html +++ b/tests/wpt/tests/css/css-color-hdr/parsing.html @@ -15,7 +15,6 @@ test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 8%, standard 2%)"); test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 99%, standard 99%)"); test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 99%, standard 99%, constrained 10%)"); - test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 1%)"); test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(constrained 20%, no-limit 80%)"); test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(dynamic-range-limit-mix(constrained 90%, no-limit 10%) 1%, no-limit 80%)"); test_valid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 1%, dynamic-range-limit-mix(constrained 2%, no-limit 10%) 80%)"); @@ -31,6 +30,7 @@ test_invalid_value("dynamic-range-limit", "hdr"); test_invalid_value("dynamic-range-limit", "sdr"); test_invalid_value("dynamic-range-limit", "low"); + test_invalid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 1%)"); test_invalid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 80% standard 20%)"); test_invalid_value("dynamic-range-limit", "dynamic-range-limit-mix(low, no-limit, 10%)"); test_invalid_value("dynamic-range-limit", "dynamic-range-limit-mix(no-limit 101%, standard 1%)"); diff --git a/tests/wpt/tests/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html b/tests/wpt/tests/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html new file mode 100644 index 00000000000..33808fbe198 --- /dev/null +++ b/tests/wpt/tests/css/css-conditional/container-queries/style-query-registered-custom-rem-change.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>CSS Container Queries Test: style() query with rem unit for registered custom property</title> +<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#style-container"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/cq-testcommon.js"></script> +<style> + @property --length { + syntax: "<length>"; + initial-value: 0px; + inherits: false; + } + + :root, body { font-size: 16px; } + #container { --length: 100px; } + + #target { color: red; } + @container style(--length: calc(1rem * 10)) { + #target { color: green; } + } +</style> +<div id="container"> + <div id="target">Should be green</div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)"); + }, "Initially, 1rem * 10 evaluates to 160px"); + + test(() => { + document.documentElement.style.fontSize = "10px"; + assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)"); + }, "Changing the :root font-size to 10px makes 1rem * 10 evaluate to 100px"); +</script> diff --git a/tests/wpt/tests/css/css-flexbox/flexbox_columns-ref.html b/tests/wpt/tests/css/css-flexbox/flexbox_columns-ref.html deleted file mode 100644 index b8c7a225698..00000000000 --- a/tests/wpt/tests/css/css-flexbox/flexbox_columns-ref.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<title>flexbox | multicol</title> -<link rel="author" href="http://opera.com" title="Opera Software"> -<style> -div { - background: black; -} -</style> - -<div>x</div> diff --git a/tests/wpt/tests/css/css-flexbox/flexbox_columns.html b/tests/wpt/tests/css/css-flexbox/flexbox_columns.html deleted file mode 100644 index d39c2db55f2..00000000000 --- a/tests/wpt/tests/css/css-flexbox/flexbox_columns.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<title>flexbox | multicol</title> -<link rel="author" href="http://opera.com" title="Opera Software"> -<link rel="help" - href="http://www.w3.org/TR/css-flexbox-1/#flex-containers"> -<link rel="match" href="flexbox_columns-ref.html"> -<style> -ul { - background: black; - padding: 0; - margin: 0; - - display: flex; - justify-content: space-around; - columns: 3; - column-rule: 1em solid red; -} -::marker { font-family:inherit; } -</style> - -<ul> - <li>one two three four</li> - <li>filler</li> - <li>filler</li> - <li>filler</li> - <li>filler</li> -</ul> diff --git a/tests/wpt/tests/css/css-forms/datetime-stacking-context-ref.html b/tests/wpt/tests/css/css-forms/datetime-stacking-context-ref.html new file mode 100644 index 00000000000..95bee383d21 --- /dev/null +++ b/tests/wpt/tests/css/css-forms/datetime-stacking-context-ref.html @@ -0,0 +1,12 @@ +<!doctype html> +<style> + #cover { + background: white; + position: fixed; + width: 100%; + height: 200px; + top: 0; + border: 1px solid black; + } +</style> +<div id="cover"></div> diff --git a/tests/wpt/tests/css/css-forms/datetime-stacking-context.html b/tests/wpt/tests/css/css-forms/datetime-stacking-context.html new file mode 100644 index 00000000000..4754cacf09d --- /dev/null +++ b/tests/wpt/tests/css/css-forms/datetime-stacking-context.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>Datetime input doesn't have stacking contexts inside</title> +<link rel="help" href="https://drafts.csswg.org/css-forms/"> <!-- a bit of a stretch but... --> +<link rel="match" href="datetime-stacking-context-ref.html"> +<style> + #cover { + background: white; + position: fixed; + width: 100%; + height: 200px; + top: 0; + border: 1px solid black; + } +</style> +<div id="cover"></div> +<input type=datetime> diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040-ref.html new file mode 100644 index 00000000000..2988cf534a9 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040-ref.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/#break"> +<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com"> +<style> + body { + margin: 0px; + } + + .grid-container { + display: grid; + grid-template-columns: repeat(4, 100px); + grid-template-rows: repeat(4, 100px); + gap: 10px; + width: 430px; + height: 430px; + } + + .grid-item { + background-color: gray; + opacity: 0.5; + border: 1px solid #000; + } + + .col-gap { + width: 0; + border-left: solid 5px blue; + } + + .col-gap1 { + position: absolute; + top: 212.5px; + left: 102.5px; + height: 217.5px; + } + + .col-gap2 { + position: absolute; + top: 0px; + left: 212.5px; + height: 430px; + } + + .col-gap3 { + position: absolute; + top: 0px; + left: 322.5px; + height: 430px; + } + + .row-gap { + height: 0px; + border-bottom: solid 5px red; + } + + .row-gap1 { + position: absolute; + top: 102.5px; + left: 325px; + width: 105px; + } + + .row-gap2 { + position: absolute; + top: 212.5px; + left: 0px; + width: 430px; + } + + .row-gap3 { + position: absolute; + top: 322.5px; + left: 0px; + width: 430px; + } +</style> + +<div class="grid-container"> + <div class="grid-item" style="grid-column: 1 / 3; grid-row: 1 / 3;"></div> + <div class="grid-item" style="grid-column: 3 / 4; grid-row: 1 / 3;"></div> +</div> + +<div class="col-gap col-gap1"> </div> +<div class="col-gap col-gap2"> </div> +<div class="col-gap col-gap3"> </div> + +<div class="row-gap row-gap1"> </div> +<div class="row-gap row-gap2"> </div> +<div class="row-gap row-gap3"> </div> diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040.html new file mode 100644 index 00000000000..4bab26db550 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-040.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title> + CSS Gap Decorations: *rule-break properly adheres to spanning-item when repeater tracks are used. +</title> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/#break"> +<link rel="match" href="grid-gap-decorations-040-ref.html"> +<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com"> +<style> + body { + margin: 0px; + } + .grid-container { + display: grid; + grid-template-columns: repeat(4, 100px); + grid-template-rows: repeat(4, 100px); + gap: 10px; + + width: 430px; + height: 430px; + + column-rule: 5px solid blue; + row-rule: 5px solid red; + } + + .grid-item { + background-color: gray; + opacity: 0.5; + border: 1px solid #000; + } + +</style> +<div class="grid-container"> + <div class="grid-item" style="grid-column: 1 / 3; grid-row: 1 / 3;"></div> + <div class="grid-item" style="grid-column: 3 / 4; grid-row: 1 / 3;"></div> +</div> diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-041-crash.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-041-crash.html new file mode 100644 index 00000000000..be3e2280b5f --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-041-crash.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title> + CSS Gap Decorations: Renderer doesn't crash when gap decorations is used on grid with no rows/columns. +</title> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/"> +<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com"> +<style> + .grid-container { + display: grid; + + column-rule: solid blue; + row-rule: dotted red; + } +</style> + +<div class="grid-container"></div> diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042-ref.html new file mode 100644 index 00000000000..ed44f7a2de3 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042-ref.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/"> +<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com"> +<style> + .grid-container { + display: grid; + grid-template-columns: repeat(4, 1fr); + width: 430px; + height: 430px; + } + + .grid-item { + background-color: gray; + opacity: 0.5; + border: 1px solid #000; + } +</style> + +<div class="grid-container"> + <div class="grid-item" style="grid-column: 1 / 3; grid-row: 1 / 2;"></div> + <div class="grid-item" style="grid-column: 3 / 4; grid-row: 1 / 3;"></div> + <div class="grid-item" style="grid-row: 2 / 4;"></div> + <div class="grid-item" style="grid-column: 2 / 4; grid-row: 3 / 4;"></div> + <div class="grid-item" style="grid-column: 2 / 3; grid-row: 2 / 3;"></div> + <div class="grid-item" style="grid-column: 4 / 5; grid-row: 1 / 4;"></div> + <div class="grid-item" style="grid-column: 1 / 4; grid-row: 4 / 5;"></div> + <div class="grid-item" style="grid-column: 4 / 5; grid-row: 4 / 5;"></div> +</div> diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042.html new file mode 100644 index 00000000000..5b2b4936980 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-042.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<title> + CSS Gap Decorations: gap decorations are not painted when there are no gaps. +</title> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/"> +<link rel="match" href="grid-gap-decorations-042-ref.html"> +<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com"> +<style> + .grid-container { + display: grid; + grid-template-columns: repeat(4, 1fr); + + width: 430px; + height: 430px; + + column-rule: 5px solid blue; + row-rule: 5px dotted red; + } + + .grid-item { + background-color: gray; + opacity: 0.5; + border: 1px solid #000; + } + +</style> +<div class="grid-container"> + <div class="grid-item" style="grid-column: 1 / 3; grid-row: 1 / 2;"></div> + <div class="grid-item" style="grid-column: 3 / 4; grid-row: 1 / 3;"></div> + <div class="grid-item" style="grid-row: 2 / 4;"></div> + <div class="grid-item" style="grid-column: 2 / 4; grid-row: 3 / 4;"></div> + <div class="grid-item" style="grid-column: 2 / 3; grid-row: 2 / 3;"></div> + <div class="grid-item" style="grid-column: 4 / 5; grid-row: 1 / 4;"></div> + <div class="grid-item" style="grid-column: 1 / 4; grid-row: 4 / 5;"></div> + <div class="grid-item" style="grid-column: 4 / 5; grid-row: 4 / 5;"></div> +</div> diff --git a/tests/wpt/tests/css/css-grid/grid-items/grid-item-inline-contribution-004.html b/tests/wpt/tests/css/css-grid/grid-items/grid-item-inline-contribution-004.html new file mode 100644 index 00000000000..a4e3cd6f3a4 --- /dev/null +++ b/tests/wpt/tests/css/css-grid/grid-items/grid-item-inline-contribution-004.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com"> +<link rel="author" title="Mozilla" href="https://www.mozilla.org/"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-grid-sizing"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/6356#issuecomment-862800005"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1957501"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="Tests the min-content contribution is re-resolved during a 2nd pass."> + +<!-- + +Quoting step 3 of css-grid-2 section 12.1. Grid Sizing Algorithm: + +" + Then, if the min-content contribution of any grid item has changed based on + the row sizes and alignment calculated in step 2, re-resolve the sizes of the + grid columns with the new min-content and max-content contributions (once + only). +" + +In this testcase initially the row size is indefinite, then resolves to 100px. +Using this information we re-resolve the columns, resulting in 50px for the +first column. + +--> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="display: grid; width: 0; grid-template: auto / auto auto;"> + <div style="background: green; height: 100%;"> + <canvas width="5" height="10" style="height: 100%;"> + </div> + <div style="background: green"> + <div style="width: 50px; height: 100px;"></div> + </div> +</div> diff --git a/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint-ranges.html b/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint-ranges.html new file mode 100644 index 00000000000..24cf8aa6dfe --- /dev/null +++ b/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint-ranges.html @@ -0,0 +1,109 @@ +<!doctype html> +<meta name="author" title="Fernando Fiori" href="mailto:ffiori@microsoft.com"> +<meta name="assert" content="HighlightRegistry.highlightsFromPoint returns the Highlights and their corresponding Ranges and StaticRanges present at the coordinates provided as argument in the right order in multi-line text."> +<link rel="help" href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/highlight/HighlightsFromPointsExplainer.md"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +::highlight(example-highlight) { + background-color: rgba(0, 255, 255, 0.5); +} +body { + font-family: monospace; +} +</style> +<span id="example-span-1">0123456789</span><br> +<span id="example-span-2">0123456789</span> +<script> + const textNode1 = document.querySelector("#example-span-1"); + const textNode2 = document.querySelector("#example-span-2"); + + function test_ranges(ranges) { + assert_equals(ranges.length, 2, 'test_ranges() should be called with exactly two ranges.'); + let big_range = ranges[0].startOffset < ranges[1].startOffset ? ranges[0] : ranges[1]; + + let highlight = new Highlight(...ranges); + CSS.highlights.set("example-highlight", highlight); + + const rect = textNode1.getBoundingClientRect(); + const characterWidth = rect.width / textNode1.textContent.length; + const characterHeight = rect.height; + + // No Highlights outside of text contents. + let x = rect.left - 1; + let y = rect.top - 1; + let highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are outside of the text contents'); + + // Get x and y coordinates between characters '0' and '1' on the first line (not highlighted). + x = rect.left + characterWidth; + y = rect.top + characterHeight / 2; + highlights = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are outside of the highlighted ranges'); + + // Get x and y coordinates between characters '2' and '3' on the first line. + x = rect.left + 3 * characterWidth; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one HighlightHitResult when the coordinates provided point at one Highlight'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the Highlight present at the coordinates provided'); + assert_array_equals(highlight_hit_results[0].ranges, [big_range], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); + + // Get x and y coordinates between characters '6' and '7' on the first line. + x = rect.left + 7 * characterWidth; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one HighlightHitResult when the coordinates provided point at one Highlight'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the Highlight present at the coordinates provided'); + assert_array_equals(highlight_hit_results[0].ranges, ranges, 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided in the right order'); + + // Get x and y coordinates to the right of the last character of the first line. + x = rect.left + 12 * characterWidth; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are to the right of the text contents'); + + // Get x and y coordinates between characters '0' and '1' on the second line. + x = rect.left + characterWidth; + y = rect.top + 1.5 * characterHeight; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one HighlightHitResult when the coordinates provided point at one Highlight'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the Highlight present at the coordinates provided'); + assert_array_equals(highlight_hit_results[0].ranges, [big_range], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); + + // Get x and y coordinates between characters '8' and '9' on the second line (not highlighted). + x = rect.left + 9 * characterWidth; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are outside of the highlighted ranges'); + + // Get x and y coordinates to the right of the last character of the second line. + x = rect.left + 12 * characterWidth; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are to the right of the text contents'); + + // Get x and y coordinates below the second line. + x = rect.left + 5 * characterWidth; + y = rect.top + 3 * characterHeight; + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are below the text contents'); + } + + test(() => { + // Set a Highlight with two nested ranges in this way: + // 01[234(56789) + // 01234567]89 + let range1 = new Range(); + range1.setStart(textNode1.childNodes[0], 5); + range1.setEnd(textNode1.childNodes[0], 10); + let range2 = new Range(); + range2.setStart(textNode1.childNodes[0], 2); + range2.setEnd(textNode2.childNodes[0], 8); + + let static_range1 = new StaticRange({startContainer: textNode1.childNodes[0], startOffset: 5, endContainer: textNode1.childNodes[0], endOffset: 10}) + let static_range2 = new StaticRange({startContainer: textNode1.childNodes[0], startOffset: 2, endContainer: textNode2.childNodes[0], endOffset: 8}) + + test_ranges([range1, range2]); + test_ranges([range2, range1]); + test_ranges([static_range1, static_range2]); + test_ranges([static_range2, static_range1]); + test_ranges([static_range1, range2]); + test_ranges([range1, static_range2]); + }, 'CSS.highlights.highlightsFromPoint() returns HighlightHitResults with the Highlights and their corresponding Ranges and StaticRanges present at the given point in the right order on multi-line text.'); +</script>
\ No newline at end of file diff --git a/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint.html b/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint.html index 5bb81bea69a..5b4e7704a4d 100644 --- a/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint.html +++ b/tests/wpt/tests/css/css-highlight-api/HighlightRegistry-highlightsFromPoint.html @@ -26,7 +26,7 @@ body { test(() => { assert_equals(CSS.highlights.highlightsFromPoint(-1,-1).length, 0); - }, 'CSS.highlights.highlightsFromPoint() should return an empty vector when called with a point outside the document.'); + }, 'CSS.highlights.highlightsFromPoint() should return an empty array when called with a point outside the document.'); test(() => { // Set two Highlights in this way: 01[234[56789]] @@ -49,35 +49,38 @@ body { // No Highlights outside of text contents. let x = rect.left - 1; let y = rect.top - 1; - let highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided are outside of the text contents'); + let highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided are outside of the text contents'); // Get x and y coordinates between '0' and '1'. x = rect.left + characterWidth; y = rect.top + rect.height / 2; highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided point at no Highlights'); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns an empty array when the coordinates provided point at no Highlights'); // Get x and y coordinates between '2' and '3'. x = rect.left + 3 * characterWidth; - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one Highlight when the coordinates provided point at one Highlight'); - assert_equals(highlights[0], highlight1, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the coordinates provided'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one HighlightHitResult when the coordinates provided point at one Highlight'); + assert_equals(highlight_hit_results[0].highlight, highlight1, 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the Highlight present at the coordinates provided'); + assert_array_equals(highlight_hit_results[0].ranges, [range1], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); // Get x and y coordinates between '6' and '7'. // Same priority for the Highlights, break tie by order of registration. x = rect.left + 7 * characterWidth; - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two Highlights when the coordinates provided point at two overlapping Highlights'); - assert_equals(highlights[0], highlight2, 'CSS.highlights.highlightsFromPoint() returns first the Highlight registered last when both Highlights present at the point provided have the same priority'); - assert_equals(highlights[1], highlight1, 'CSS.highlights.highlightsFromPoint() returns last the Highlight registered first when both Highlights present at the point provided have the same priority'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two HighlightHitResults when the coordinates provided point at two overlapping Highlights'); + assert_equals(highlight_hit_results[0].highlight, highlight2, 'CSS.highlights.highlightsFromPoint() returns first a HighlightHitResult with the Highlight registered last when both Highlights present at the point provided have the same priority'); + assert_equals(highlight_hit_results[1].highlight, highlight1, 'CSS.highlights.highlightsFromPoint() returns last a HighlightHitResult with the Highlight registered first when both Highlights present at the point provided have the same priority'); + assert_array_equals(highlight_hit_results[0].ranges, [range2], 'CSS.highlights.highlightsFromPoint() returns first a HighlightHitResult with the ranges of the Highlight present on top at the coordinates provided'); + assert_array_equals(highlight_hit_results[1].ranges, [range1], 'CSS.highlights.highlightsFromPoint() returns last a HighlightHitResult with the ranges of the Highlight present at the bottom at the coordinates provided'); // Now highlight1 should be first because it's got higher priority. highlight1.priority = 2; highlight2.priority = 1; - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two Highlights when the coordinates provided point at two overlapping Highlights'); - assert_equals(highlights[0], highlight1, 'CSS.highlights.highlightsFromPoint() returns first the Highlight with higher priority when there are two Highlights present at the point provided'); - assert_equals(highlights[1], highlight2, 'CSS.highlights.highlightsFromPoint() returns last the Highlight with lower priority when there are two Highlights present at the point provided'); - }, 'CSS.highlights.highlightsFromPoint() returns Highlights present at the given point in the right order.'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two HighlightHitResults when the coordinates provided point at two overlapping Highlights'); + assert_equals(highlight_hit_results[0].highlight, highlight1, 'CSS.highlights.highlightsFromPoint() returns first a HighlightHitResult with the Highlight with higher priority when there are two Highlights present at the point provided'); + assert_equals(highlight_hit_results[1].highlight, highlight2, 'CSS.highlights.highlightsFromPoint() returns last a HighlightHitResult with the Highlight with lower priority when there are two Highlights present at the point provided'); + }, 'CSS.highlights.highlightsFromPoint() returns the Highlights with their corresponding ranges present at the given point in the right order.'); </script>
\ No newline at end of file diff --git a/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html new file mode 100644 index 00000000000..2869d38a982 --- /dev/null +++ b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and shape function with single-value arc radius</title> +</head> +<style> +@keyframes animate-shape { + from { + clip-path: shape(from 40px 100px, arc to 200px 100px of 50% 50% small cw, arc to 0 100px of 30% 30% small cw); + } + to { + clip-path: shape(from 40px 100px, arc to 200px 100px of 30% 30% small cw, arc to 0 100px of calc(10px + 45%) calc(10px + 45%) small cw); + } +} +#shape { + width: calc(500px / sqrt(2)); + height: calc(500px / sqrt(2)); + background: green; + animation: animate-shape 100s; + animation-play-state: paused; + animation-timing-function: steps(2, start); +} +</style> + +<div id="shape"></div> +</html> diff --git a/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius.html b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius.html new file mode 100644 index 00000000000..aa91e1828a7 --- /dev/null +++ b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test animating single-value arc radius of the shape() function</title> + <link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-shape"> + <link rel="match" href="clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html"> + <meta name="fuzzy" content="maxDifference=0-10;totalPixels=0-360"> +</head> +<style> +@keyframes animate-shape { + from { + clip-path: shape(from 40px 100px, arc to 200px 100px of 50% small cw, arc to 0 100px of 30% small cw); + } + to { + clip-path: shape(from 40px 100px, arc to 200px 100px of 30% small cw, arc to 0 100px of calc(10px + 45%) small cw); + } +} +#shape { + width: 400px; + height: 300px; + background: green; + animation: animate-shape 100s; + animation-play-state: paused; + animation-timing-function: steps(2, start); +} +</style> + +<div id="shape"></div> +</html> diff --git a/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape.html b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape.html index 6d85c2a06b4..f725e1fc6fa 100644 --- a/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape.html +++ b/tests/wpt/tests/css/css-masking/animations/clip-path-interpolation-shape.html @@ -145,15 +145,28 @@ test_interpolation({ test_interpolation({ property: 'clip-path', - from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', - to: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px cw rotate 270deg small, arc to 25% 20px of 10px 5px small cw)' + from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', + to: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px 20px cw rotate 270deg small, arc to 25% 20px of 10px 5px small cw)' }, [ {at: -0.3, expect: 'shape(from 2% 2px, arc to 18% -12px of 7px 17px, arc by 12% -2px of 33px 33px rotate -42deg cw large , arc to 25% 20px of 10px 5px)'}, - {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px)'}, + {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px)'}, {at: 0.3, expect: 'shape(from 8% 8px, arc to 12% -18px of 13px 23px, arc by 18% -8px of 27px 27px rotate 102deg cw large, arc to 25% 20px of 10px 5px cw)'}, - {at: 0.5, expect: 'shape(from 10% 10px, arc to 10% -20px of 15px 25px, arc by 20% -10px of 25px rotate 150deg cw large, arc to 25% 20px of 10px 5px cw)'}, - {at: 1, expect: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px rotate 270deg cw, arc to 25% 20px of 10px 5px cw)'}, - {at: 1.5, expect: 'shape(from 20% 20px, arc to 0% -30px of 25px 35px, arc by 30% -20px of 15px rotate 390deg cw, arc to 25% 20px of 10px 5px cw)'}, + {at: 0.5, expect: 'shape(from 10% 10px, arc to 10% -20px of 15px 25px, arc by 20% -10px of 25px 25px rotate 150deg cw large, arc to 25% 20px of 10px 5px cw)'}, + {at: 1, expect: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px 20px rotate 270deg cw, arc to 25% 20px of 10px 5px cw)'}, + {at: 1.5, expect: 'shape(from 20% 20px, arc to 0% -30px of 25px 35px, arc by 30% -20px of 15px 15px rotate 390deg cw, arc to 25% 20px of 10px 5px cw)'}, +]); + +test_interpolation({ + property: 'clip-path', + from: 'shape(from 5% 5px, arc to 15% -15px of 10px, arc by 15% -5px of 30% cw rotate 30deg large, arc to 25% 20px of 10% small)', + to: 'shape(from 15% 15px, arc to 5% -25px of 15%, arc by 25% -15px of 12rem cw rotate 270deg small, arc to 15% 20px of 20% small cw)' +}, [ + {at: -0.3, expect: 'shape(from 2% 2px, arc to 18% -12px of calc(-4.5% + 13px), arc by 12% -2px of calc(39% - 57.6px) cw large rotate -42deg, arc to 28% 20px of 7%)'}, + {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of calc(0% + 10px), arc by 15% -5px of 30% cw large rotate 30deg, arc to 25% 20px of 10%)'}, + {at: 0.3, expect: 'shape(from 8% 8px, arc to 12% -18px of calc(4.5% + 7px), arc by 18% -8px of calc(21% + 57.6px) rotate 102deg cw large, arc to 22% 20px of 13% cw)'}, + {at: 0.5, expect: 'shape(from 10% 10px, arc to 10% -20px of calc(7.5% + 5px), arc by 20% -10px of calc(15% + 96px) cw large rotate 150deg, arc to 20% 20px of 15% cw)'}, + {at: 1, expect: 'shape(from 15% 15px, arc to 5% -25px of 15%, arc by 25% -15px of calc(0% + 192px) cw rotate 270deg, arc to 15% 20px of 20% cw)'}, + {at: 1.5, expect: 'shape(from 20% 20px, arc to 0% -30px of calc(22.5% - 5px), arc by 30% -20px of calc(-15% + 288px) cw rotate 390deg, arc to 10% 20px of 25% cw)'}, ]); test_interpolation({ @@ -254,28 +267,28 @@ test_interpolation({ test_interpolation({ property: 'clip-path', - from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', + from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', to: 'path("M 15 15 A 20,30 0 0,0 5,-25 a 20,20 270 0,1 25,-15 A 10,5 0 0,0 25 20")', }, [ - {at: -0.3, expect: 'shape(from calc(6.5% - 4.5px) 2px, arc to calc(19.5% - 1.5px) -12px of 7px 17px, arc by calc(19.5% - 7.5px) -2px of 33px cw large rotate -42deg, arc to calc(32.5% - 7.5px) 20px of 10px 5px)'}, - {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)'}, - {at: 0.3, expect: 'shape(from calc(3.5% + 4.5px) 8px, arc to calc(10.5% + 1.5px) -18px of 13px 23px, arc by calc(10.5% + 7.5px) -8px of 27px cw large rotate 102deg, arc to calc(17.5% + 7.5px) 20px of 10px 5px)'}, - {at: 0.5, expect: 'shape(from calc(2.5% + 7.5px) 10px, arc to calc(7.5% + 2.5px) -20px of 15px 25px, arc by calc(7.5% + 12.5px) -10px of 25px cw large rotate 150deg, arc to calc(12.5% + 12.5px) 20px of 10px 5px)'}, - {at: 1, expect: 'shape(from calc(0% + 15px) 15px, arc to calc(0% + 5px) -25px of 20px 30px, arc by calc(0% + 25px) -15px of 20px cw rotate 270deg, arc to calc(0% + 25px) 20px of 10px 5px)'}, - {at: 1.5, expect: 'shape(from calc(-2.5% + 22.5px) 20px, arc to calc(-7.5% + 7.5px) -30px of 25px 35px, arc by calc(-7.5% + 37.5px) -20px of 15px cw rotate 390deg, arc to calc(-12.5% + 37.5px) 20px of 10px 5px)'}, + {at: -0.3, expect: 'shape(from calc(6.5% - 4.5px) 2px, arc to calc(19.5% - 1.5px) -12px of 7px 17px, arc by calc(19.5% - 7.5px) -2px of 33px 33px cw large rotate -42deg, arc to calc(32.5% - 7.5px) 20px of 10px 5px)'}, + {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)'}, + {at: 0.3, expect: 'shape(from calc(3.5% + 4.5px) 8px, arc to calc(10.5% + 1.5px) -18px of 13px 23px, arc by calc(10.5% + 7.5px) -8px of 27px 27px cw large rotate 102deg, arc to calc(17.5% + 7.5px) 20px of 10px 5px)'}, + {at: 0.5, expect: 'shape(from calc(2.5% + 7.5px) 10px, arc to calc(7.5% + 2.5px) -20px of 15px 25px, arc by calc(7.5% + 12.5px) -10px of 25px 25px cw large rotate 150deg, arc to calc(12.5% + 12.5px) 20px of 10px 5px)'}, + {at: 1, expect: 'shape(from calc(0% + 15px) 15px, arc to calc(0% + 5px) -25px of 20px 30px, arc by calc(0% + 25px) -15px of 20px 20px cw rotate 270deg, arc to calc(0% + 25px) 20px of 10px 5px)'}, + {at: 1.5, expect: 'shape(from calc(-2.5% + 22.5px) 20px, arc to calc(-7.5% + 7.5px) -30px of 25px 35px, arc by calc(-7.5% + 37.5px) -20px of 15px 15px cw rotate 390deg, arc to calc(-12.5% + 37.5px) 20px of 10px 5px)'}, ]); test_interpolation({ property: 'clip-path', from: 'path("M 5 5 A 10,20 0 0,0 15,-15 a 30,30 30 1,1 15,-5 A 10,5 0 0,0 25 20")', - to: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px cw rotate 270deg small, arc to 25px 20px of 10px 5px small cw)' // ccw, cw, cw + to: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px 20px cw rotate 270deg small, arc to 25px 20px of 10px 5px small cw)' // ccw, cw, cw }, [ {at: -0.3, expect: 'shape(from 2px 2px, arc to 18px -12px of 7px 17px, arc by 12px -2px of 33px 33px rotate -42deg cw large, arc to 25px 20px of 10px 5px)'}, - {at: 0, expect: 'shape(from 5px 5px, arc to 15px -15px of 10px 20px, arc by 15px -5px of 30px cw rotate 30deg large, arc to 25px 20px of 10px 5px)'}, + {at: 0, expect: 'shape(from 5px 5px, arc to 15px -15px of 10px 20px, arc by 15px -5px of 30px 30px cw rotate 30deg large, arc to 25px 20px of 10px 5px)'}, {at: 0.3, expect: 'shape(from 8px 8px, arc to 12px -18px of 13px 23px, arc by 18px -8px of 27px 27px rotate 102deg cw large, arc to 25px 20px of 10px 5px cw)'}, - {at: 0.5, expect: 'shape(from 10px 10px, arc to 10px -20px of 15px 25px, arc by 20px -10px of 25px rotate 150deg cw large, arc to 25px 20px of 10px 5px cw)'}, - {at: 1, expect: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px rotate 270deg cw, arc to 25px 20px of 10px 5px cw)'}, - {at: 1.5, expect: 'shape(from 20px 20px, arc to 0px -30px of 25px 35px, arc by 30px -20px of 15px rotate 390deg cw, arc to 25px 20px of 10px 5px cw)'}, + {at: 0.5, expect: 'shape(from 10px 10px, arc to 10px -20px of 15px 25px, arc by 20px -10px of 25px 25px rotate 150deg cw large, arc to 25px 20px of 10px 5px cw)'}, + {at: 1, expect: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px 20px rotate 270deg cw, arc to 25px 20px of 10px 5px cw)'}, + {at: 1.5, expect: 'shape(from 20px 20px, arc to 0px -30px of 25px 35px, arc by 30px -20px of 15px 15px rotate 390deg cw, arc to 25px 20px of 10px 5px cw)'}, ]); </script> diff --git a/tests/wpt/tests/css/css-masking/clip-path/clip-path-shape-011.html b/tests/wpt/tests/css/css-masking/clip-path/clip-path-shape-011.html new file mode 100644 index 00000000000..fc1927591e0 --- /dev/null +++ b/tests/wpt/tests/css/css-masking/clip-path/clip-path-shape-011.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and shape function with single-value arc radius</title> + <link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-shape"> + <link rel="match" href="reference/clip-path-shape-arc-ref.html"> + <meta name="assert" content="When providing one radius value with percentage, the percentage should be relative to the diagonal."> +<meta name="fuzzy" content="maxDifference=0-64;totalPixels=0-128"> +</head> +<style> +#shape { + width: 400px; + height: 300px; + background: green; + clip-path: shape( + from 0px 100px, + arc to 20px 100px of 10% large cw, + arc to 100px 20px of 5% small, + arc to 0 100px of calc(10px + 15%) + rotate 30deg); +} +</style> + +<body> + <div id="shape"></div> +</body> +</html> diff --git a/tests/wpt/tests/css/css-masking/clip-path/reference/clip-path-shape-arc-ref.html b/tests/wpt/tests/css/css-masking/clip-path/reference/clip-path-shape-arc-ref.html new file mode 100644 index 00000000000..9cbe55de210 --- /dev/null +++ b/tests/wpt/tests/css/css-masking/clip-path/reference/clip-path-shape-arc-ref.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and shape function with single-value arc radius</title> + <link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-shape"> +</head> +<style> +#shape { + /* 500/sqrt(2) ~= 353 */ + width: 353px; + height: 353px; + background: green; + clip-path: shape( + from 0px 100px, + arc to 20px 100px of 10% large cw, + arc to 100px 20px of 5% small, + arc to 0 100px of calc(10px + 15%) + rotate 30deg); +} +</style> + +<body> + <div id="shape"></div> +</body> +</html> diff --git a/tests/wpt/tests/css/css-masking/parsing/clip-path-shape-parsing.html b/tests/wpt/tests/css/css-masking/parsing/clip-path-shape-parsing.html index 5a4c7415bb4..b889ee01805 100644 --- a/tests/wpt/tests/css/css-masking/parsing/clip-path-shape-parsing.html +++ b/tests/wpt/tests/css/css-masking/parsing/clip-path-shape-parsing.html @@ -29,8 +29,10 @@ test_valid_value("clip-path", "shape(from 10px 10px, curve to 50px 20px with 10r test_valid_value("clip-path", "shape(from 10px 10px, curve by 50px 20px with 10rem 1px / 20vh 1ch)"); test_valid_value("clip-path", "shape(from 10px 10px, smooth to 50px 20px with 10rem 1%)"); test_valid_value("clip-path", "shape(from 10px 10px, smooth to 50px 1pt)"); -test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)", "shape(from 10px 10px, arc to 50px 1pt of 10px)"); -test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 1pt of 10px)"); +test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)"); +test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10%)"); +test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)"); +test_valid_value("clip-path", "shape(from 10px 10px, arc to 50px 1pt of 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 1pt of 10px)"); test_valid_value("clip-path", "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)", "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)"); test_valid_value("clip-path", "shape(evenodd from 0px 0px, close)"); diff --git a/tests/wpt/tests/css/css-multicol/column-height-009-ref.html b/tests/wpt/tests/css/css-multicol/column-height-009-ref.html index 034440ebd5c..4696d79695b 100644 --- a/tests/wpt/tests/css/css-multicol/column-height-009-ref.html +++ b/tests/wpt/tests/css/css-multicol/column-height-009-ref.html @@ -32,7 +32,7 @@ <div class="item">i<br>j</div> <div class="item">o<br>p</div> </div> - <div class="rule" style="height:100px;"></div> + <div class="rule" style="height:160px;"></div> <div class="column"> <div class="item">e<br>f</div> <div class="item">k<br>l</div> diff --git a/tests/wpt/tests/css/css-multicol/crashtests/repeated-table-column.html b/tests/wpt/tests/css/css-multicol/crashtests/repeated-table-column.html new file mode 100644 index 00000000000..0d6a1accfd1 --- /dev/null +++ b/tests/wpt/tests/css/css-multicol/crashtests/repeated-table-column.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://issues.chromium.org/issues/420267099"> +<div style="columns:2; column-fill:auto; height:100px;"> + <div style="display:table;"> + <div style="display:table-header-group; break-inside:avoid;"> + <div style="display:table;"> + <div id="col" style="display:table-column;"></div> + <div style="width:10px; height:10px;"></div> + </div> + </div> + <div style="height:150px;"></div> + </div> +</div> +<script> + col.offsetLeft; +</script> diff --git a/tests/wpt/tests/css/css-multicol/parsing/column-rule-color-invalid.html b/tests/wpt/tests/css/css-multicol/parsing/column-rule-color-invalid.html index 015defb7560..da8dba0a73c 100644 --- a/tests/wpt/tests/css/css-multicol/parsing/column-rule-color-invalid.html +++ b/tests/wpt/tests/css/css-multicol/parsing/column-rule-color-invalid.html @@ -13,7 +13,6 @@ <script> test_invalid_value("column-rule-color", "auto"); -test_invalid_value("column-rule-color", "green blue"); test_invalid_value("column-rule-color", "green, blue"); </script> </body> diff --git a/tests/wpt/tests/css/css-multicol/parsing/column-rule-style-invalid.html b/tests/wpt/tests/css/css-multicol/parsing/column-rule-style-invalid.html index db367c273f4..e8f2ab60c47 100644 --- a/tests/wpt/tests/css/css-multicol/parsing/column-rule-style-invalid.html +++ b/tests/wpt/tests/css/css-multicol/parsing/column-rule-style-invalid.html @@ -12,7 +12,6 @@ <body> <script> test_invalid_value("column-rule-style", "auto"); -test_invalid_value("column-rule-style", "double dashed"); </script> </body> </html> diff --git a/tests/wpt/tests/css/css-multicol/parsing/column-rule-width-invalid.html b/tests/wpt/tests/css/css-multicol/parsing/column-rule-width-invalid.html index 0bdbbecb8ca..77f55e09d93 100644 --- a/tests/wpt/tests/css/css-multicol/parsing/column-rule-width-invalid.html +++ b/tests/wpt/tests/css/css-multicol/parsing/column-rule-width-invalid.html @@ -18,7 +18,6 @@ test_invalid_value("column-rule-width", "10"); test_invalid_value("column-rule-width", "-20px"); test_invalid_value("column-rule-width", "30%"); -test_invalid_value("column-rule-width", "medium 40px"); </script> </body> </html> diff --git a/tests/wpt/tests/css/css-position/overlay/WEB_FEATURES.yml b/tests/wpt/tests/css/css-position/overlay/WEB_FEATURES.yml new file mode 100644 index 00000000000..a1a4402ee42 --- /dev/null +++ b/tests/wpt/tests/css/css-position/overlay/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: overlay + files: "**" diff --git a/tests/wpt/tests/css/css-sizing/contain-intrinsic-size/parsing/from-element.tentative.html b/tests/wpt/tests/css/css-sizing/contain-intrinsic-size/parsing/from-element.tentative.html new file mode 100644 index 00000000000..fe99ccb23d9 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/contain-intrinsic-size/parsing/from-element.tentative.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic Size Test: intrinsic-size with from-element</title> +<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#intrinsic-size-override"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("contain-intrinsic-size", "from-element"); +</script> +</body> +</html> + diff --git a/tests/wpt/tests/css/css-sizing/image-max-width-and-height-behaves-as-auto.html b/tests/wpt/tests/css/css-sizing/image-max-width-and-height-behaves-as-auto.html new file mode 100644 index 00000000000..dcb00ba6a5c --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/image-max-width-and-height-behaves-as-auto.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#min-max-widths"> +<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers"> +<meta name="assert" content="When computed logical width is auto, computed logical height behaves as auto, +the used logical height should be determined with respect to any max logical width constraint."> +<link rel="match" href="../reference/ref-filled-green-100px-square-only.html"> +<style> +.container { + width: 100px; +} +img { + max-width: 100%; + height: 100%; +} +</style> +</head> +<body> + <p>Test passes if there is a filled green square.</p> + <div class="container"> + <img src="aspect-ratio/support/200x200-green.png"/> + </div> +</body> +</html> diff --git a/tests/wpt/tests/css/css-sizing/resources/iframe-contents-unsized.html b/tests/wpt/tests/css/css-sizing/resources/iframe-contents-unsized.html new file mode 100644 index 00000000000..db1931a27d5 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/resources/iframe-contents-unsized.html @@ -0,0 +1,7 @@ +<!doctype HTML> +<head> +<style> + * { margin: 0 } +</style> +</head> +<div style="width: 100px; height: 400px"></div> diff --git a/tests/wpt/tests/css/css-sizing/resources/iframe-contents.html b/tests/wpt/tests/css/css-sizing/resources/iframe-contents.html new file mode 100644 index 00000000000..3b7406e1e40 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/resources/iframe-contents.html @@ -0,0 +1,8 @@ +<!doctype HTML> +<head> +<style> + * { margin: 0 } +</style> +<meta name="responsive-embedded-sizing"> +</head> +<div style="width: 100px; height: 400px"></div> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-no-match-element.sub.tentative.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-no-match-element.sub.tentative.html new file mode 100644 index 00000000000..08dda4e6b76 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-no-match-element.sub.tentative.html @@ -0,0 +1,12 @@ +<!doctype HTML> +<title>Test that a cross-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-unsized-ref.html"> +<style> +iframe { + border: 1px solid black; +} +</style> +<iframe frameborder=0 scrolling=no src="http://{{hosts[alt][]}}:{{ports[http][0]}}/css/css-sizing/resources/iframe-contents.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-not-embedded-sized.sub.tentative.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-not-embedded-sized.sub.tentative.html new file mode 100644 index 00000000000..d9b33973a04 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin-not-embedded-sized.sub.tentative.html @@ -0,0 +1,13 @@ +<!doctype HTML> +<title>Test that a cross-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-unsized-ref.html"> +<style> +iframe { + border: 1px solid black; + contain-intrinsic-size: from-element; +} +</style> +<iframe frameborder=0 scrolling=no src="http://{{hosts[alt][]}}:{{ports[http][0]}}/css/css-sizing/resources/iframe-contents-unsized.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html new file mode 100644 index 00000000000..22f6f1d1581 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-cross-origin.sub.tentative.html @@ -0,0 +1,13 @@ +<!doctype HTML> +<title>Test that a cross-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-ref.html"> +<style> +iframe { + border: 1px solid black; + contain-intrinsic-size: from-element; +} +</style> +<iframe frameborder=0 src="http://{{hosts[alt][]}}:{{ports[http][0]}}/css/css-sizing/resources/iframe-contents.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-no-match-element.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-no-match-element.html new file mode 100644 index 00000000000..685eb60f123 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-no-match-element.html @@ -0,0 +1,12 @@ +<!doctype HTML> +<title>Test that a same-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-unsized-ref.html"> +<style> +iframe { + border: 1px solid black; +} +</style> +<iframe frameborder=0 scrolling=no src="resources/iframe-contents.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-not-embedded-sized.tentative.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-not-embedded-sized.tentative.html new file mode 100644 index 00000000000..0d1f91c5789 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-not-embedded-sized.tentative.html @@ -0,0 +1,13 @@ +<!doctype HTML> +<title>Test that a same-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-unsized-ref.html"> +<style> +iframe { + border: 1px solid black; + contain-intrinsic-size: from-element; +} +</style> +<iframe frameborder=0 scrolling=no src="resources/iframe-contents-unsized.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-ref.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-ref.html new file mode 100644 index 00000000000..c446474f71a --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-ref.html @@ -0,0 +1,10 @@ +<!doctype HTML> +<style> +div { + width: 300px; + height: 400px; + border: 1px solid black; +} +</style> +<div> +</div> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe-unsized-ref.html b/tests/wpt/tests/css/css-sizing/responsive-iframe-unsized-ref.html new file mode 100644 index 00000000000..2fa633e086d --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe-unsized-ref.html @@ -0,0 +1,10 @@ +<!doctype HTML> +<style> +div { + width: 300px; + height: 150px; + border: 1px solid black; +} +</style> +<div> +</div> diff --git a/tests/wpt/tests/css/css-sizing/responsive-iframe.tentative.html b/tests/wpt/tests/css/css-sizing/responsive-iframe.tentative.html new file mode 100644 index 00000000000..229cf018449 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/responsive-iframe.tentative.html @@ -0,0 +1,13 @@ +<!doctype HTML> +<title>Test that a same-origin iframe is responsively sized.</title> +<link rel="author" href="mailto:chrishtr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-sizing/"> +<link rel="match" href="responsive-iframe-ref.html"> +<style> +iframe { + border: 1px solid black; + contain-intrinsic-size: from-element; +} +</style> +<iframe frameborder=0 src="resources/iframe-contents.html"> +</iframe> diff --git a/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001-ref.html b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001-ref.html new file mode 100644 index 00000000000..ca95e197462 --- /dev/null +++ b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001-ref.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +#container { + font-family: Ahem; + font-size: 40px; +} +</style> +<div id="container"> + <div>1国国国国国国国国国国</div> + <div>1国国国国国国国国国国</div> + <div>1国国国国国国国国国国国国</div> + <div>1国国国国国国国国国国国国</div> +</div> diff --git a/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001.html b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001.html new file mode 100644 index 00000000000..80c46f54d20 --- /dev/null +++ b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-edit-001.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="help" href="https://drafts.csswg.org/css-text-4/#text-autospace-property"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="match" href="text-autospace-edit-001-ref.html"> +<style> +#container { + font-family: Ahem; + font-size: 40px; +} +</style> +<div id="container"> + <div data-append="10">1国国国国国国国国国国</div> + <div data-append="11">1国国国国国国国国国国国国</div> +</div> +<script> +for (const reference of document.querySelectorAll("[data-append]")) { + // Split the `textContent` at the `data-append` offset. + const text = reference.textContent; + const offset = parseInt(reference.dataset.append); + const initiaL_text = text.substring(0, offset); + const append_text = text.substring(offset); + + // Create a `<div>` with the `initial_text`, then append `append_text` + // one character at a time, with a forced layout. + const element = document.createElement("div"); + const text_node = document.createTextNode(initiaL_text); + element.appendChild(text_node); + reference.after(element); + for (const ch of append_text) { + element.offsetTop; + text_node.appendData(ch); + } +} +</script> diff --git a/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001-ref.html b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001-ref.html new file mode 100644 index 00000000000..b02b4f7a20d --- /dev/null +++ b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001-ref.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +#container { + font-family: Ahem; + font-size: 40px; + text-autospace: no-autospace; + + span { + margin-left: calc(1em / 8); + margin-right: calc(1em / 8); + } +} +</style> +<div id="container"> + <div class="test">国︀国</div> + <div class="test">国︀<span>A</span></div> + <div class="test">A︀<span>国</span></div> + <div class="test">国󠄀国</div> + <div class="test">国󠄀<span>A</span></div> + <div class="test">A󠄀<span>国</span></div> +</div> diff --git a/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001.html b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001.html new file mode 100644 index 00000000000..31c7bbf6073 --- /dev/null +++ b/tests/wpt/tests/css/css-text/text-autospace/text-autospace-vs-001.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="help" href="https://drafts.csswg.org/css-text-4/#text-autospace-property"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="match" href="text-autospace-vs-001-ref.html"> +<style> +#container { + font-family: Ahem; + font-size: 40px; +} +</style> +<div id="container"> + <div class="test">国︀国</div> + <div class="test">国︀A</div> + <div class="test">A︀国</div> + <div class="test">国󠄀国</div> + <div class="test">国󠄀A</div> + <div class="test">A󠄀国</div> +</div> diff --git a/tests/wpt/tests/css/css-text/word-break/reference/word-break-keep-all-u002d-ref.html b/tests/wpt/tests/css/css-text/word-break/reference/word-break-keep-all-u002d-ref.html new file mode 100644 index 00000000000..4a6553cfe83 --- /dev/null +++ b/tests/wpt/tests/css/css-text/word-break/reference/word-break-keep-all-u002d-ref.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<style> +#container { + font-size: 20px; + width: 3ch; +} +</style> +<div id="container"> + <div>AB-CD-EF</div> + <div>12-34-56</div> +</div> diff --git a/tests/wpt/tests/css/css-text/word-break/word-break-keep-all-u002d.html b/tests/wpt/tests/css/css-text/word-break/word-break-keep-all-u002d.html new file mode 100644 index 00000000000..df3ebb3f221 --- /dev/null +++ b/tests/wpt/tests/css/css-text/word-break/word-break-keep-all-u002d.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-keep-all"> +<link rel="match" href="reference/word-break-keep-all-u002d-ref.html"> +<style> +#container { + font-size: 20px; + width: 3ch; + word-break: keep-all; +} +</style> +<div id="container"> + <div>AB-CD-EF</div> + <div>12-34-56</div> +</div> diff --git a/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html b/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html index 8e56f621714..7098270a392 100644 --- a/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html +++ b/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html @@ -14,16 +14,36 @@ 'use strict'; runPropertyTests('column-rule-style', [ - { syntax: 'none' }, - { syntax: 'hidden' }, - { syntax: 'dotted' }, - { syntax: 'dashed' }, - { syntax: 'solid' }, - { syntax: 'double' }, - { syntax: 'groove' }, - { syntax: 'ridge' }, - { syntax: 'inset' }, - { syntax: 'outset' } + { syntax: 'none', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'hidden', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'dotted', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'dashed', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'solid', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'double', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'groove', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'ridge', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'inset', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { syntax: 'outset', + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + } ]); </script> diff --git a/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html b/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html index bd3c0ac8f43..8f09d1cb45a 100644 --- a/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html +++ b/tests/wpt/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html @@ -13,30 +13,29 @@ <script> 'use strict'; -function assert_is_zero_px(result) { - assert_style_value_equals(result, new CSSUnitValue(0, 'px')); -} - runPropertyTests('column-rule-width', [ - // Computed value is 0 when column-rule-style is 'none'. - // FIXME: Add separate test where column-rule-style is not 'none' or 'hidden'. { syntax: 'thin', - computed: (_, result) => assert_is_zero_px(result) + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') }, { syntax: 'medium', - computed: (_, result) => assert_is_zero_px(result) + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') }, { syntax: 'thick', - computed: (_, result) => assert_is_zero_px(result) + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') }, { syntax: '<length>', specified: assert_is_equal_with_range_handling, - computed: (_, result) => assert_is_zero_px(result) + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') }, ]); +runUnsupportedPropertyTests('column-rule-width', [ + 'thin', 'medium', 'thick', '2px', '3px', + '4px 5px', 'thin medium thick', +]); + </script> diff --git a/tests/wpt/tests/css/css-values/if-conditionals.html b/tests/wpt/tests/css/css-values/if-conditionals.html index caead7864d5..f6d981798ae 100644 --- a/tests/wpt/tests/css/css-values/if-conditionals.html +++ b/tests/wpt/tests/css/css-values/if-conditionals.html @@ -37,6 +37,21 @@ inherits: true; initial-value: 3; } + @property --angle { + syntax: "<angle>"; + inherits: true; + initial-value: 3deg; + } + @property --time { + syntax: "<time>"; + inherits: true; + initial-value: 3s; + } + @property --resolution { + syntax: "<resolution>"; + inherits: true; + initial-value: 3dpi; + } div { font-size: 30px; } @@ -511,6 +526,122 @@ [['--length', 'attr(data-foo type(<length>))']], 'false_value'); + // style() queries with range syntax in the condition, literals on both sides of equation + test_if_with_custom_properties('if(style(10em > 3px): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(1em > 1px): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(7px > 3px): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(3px > 3px): true_value; else: false_value)', [], 'false_value'); + test_if_with_custom_properties('if(style(3turn > 3deg): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(3turn <= 3deg): true_value; else: false_value)', [], 'false_value'); + test_if_with_custom_properties('if(style(3% >= 3%): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(3s > 3ms): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(3dppx > 96dpi): true_value; else: false_value)', [], 'true_value'); + + // style() queries with range syntax in the condition, simple custom properties in the condition + test_if_with_custom_properties('if(style(--x <= 3): true_value; else: false_value)', + [['--x', '3']], + 'true_value'); + test_if_with_custom_properties('if(style(--x >= --y): true_value; else: false_value)', + [['--x', '3'], ['--y', '3']], + 'true_value'); + test_if_with_custom_properties('if(style(--length > 3px): true_value; else: false_value)', + [['--length', '11px']], + 'true_value'); + test_if_with_custom_properties('if(style(--x > 3px): true_value; else: false_value)', + [['--x', '11px']], + 'true_value'); + test_if_with_custom_properties('if(style(--number >= 3): true_value; else: false_value)', + [['--number', '3']], + 'true_value'); + test_if_with_custom_properties('if(style(--x >= 3): true_value; else: false_value)', + [['--x', '3']], + 'true_value'); + test_if_with_custom_properties('if(style(--percentage > 3%): true_value; else: false_value)', + [['--percentage', '5%']], + 'true_value'); + test_if_with_custom_properties('if(style(--x > 3%): true_value; else: false_value)', + [['--x', '5%']], + 'true_value'); + test_if_with_custom_properties('if(style(--angle < 1turn): true_value; else: false_value)', + [['--angle', '1deg']], + 'true_value'); + test_if_with_custom_properties('if(style(--x < 1turn): true_value; else: false_value)', + [['--x', '1deg']], + 'true_value'); + test_if_with_custom_properties('if(style(--time <= 1000ms): true_value; else: false_value)', + [['--time', '1s']], + 'true_value'); + test_if_with_custom_properties('if(style(--x <= 1000ms): true_value; else: false_value)', + [['--x', '1s']], + 'true_value'); + test_if_with_custom_properties('if(style(3dppx > --resolution): true_value; else: false_value)', + [['--resolution', '96dpi']], + 'true_value'); + test_if_with_custom_properties('if(style(3dppx > --x): true_value; else: false_value)', + [['--x', '96dpi']], + 'true_value'); + + // style() queries with range syntax in the condition, invalid custom properties in the condition + test_if_with_custom_properties('if(style(--x + 1 >= --y): true_value; else: false_value)', + [['--x', '5'], ['--y', '3']], + 'false_value'); + test_if_with_custom_properties('if(style(--x >= --y + 1): true_value; else: false_value)', + [['--x', '5'], ['--y', '3']], + 'false_value'); + test_if_with_custom_properties('if(style(calc(--x + 1) >= --y): true_value; else: false_value)', + [['--x', '5'], ['--y', '3']], + 'false_value'); + test_if_with_custom_properties('if(style(--x >= calc(--y + 1)): true_value; else: false_value)', + [['--x', '5'], ['--y', '3']], + 'false_value'); + + // style() queries with range syntax in the condition, custom properties with functions in the condition + test_if_with_custom_properties('if(style(--x >= calc(3px + 3px)): true_value; else: false_value)', + [['--x', '7px']], + 'true_value'); + test_if_with_custom_properties('if(style(calc(var(--x) + 1) >= var(--y)): true_value; else: false_value)', + [['--x', '5'], ['--y', '3']], + 'true_value'); + test_if_with_custom_properties('if(style(var(--x) >= --x): true_value; else: false_value)', + [['--x', '3']], + 'true_value'); + + // style() queries with range syntax in the condition, incompatible types in the range. + test_if_with_custom_properties('if(style(3px > 3): true_value; else: false_value)', + [], + 'false_value'); + test_if_with_custom_properties('if(style(3em > 3deg): true_value; else: false_value)', + [], + 'false_value'); + test_if_with_custom_properties('if(style(1px >= 1%) or style(1px <= 1%): true_value; else: false_value)', + [], + 'false_value'); + test_if_with_custom_properties('if(style(--length > 3): true_value; else: false_value)', + [['--length', '11em']], + 'false_value'); + test_if_with_custom_properties('if(style(--number > 3px): true_value; else: false_value)', + [['--number', '11']], + 'false_value'); + test_if_with_custom_properties('if(style(--x >= 3): true_value; else: false_value)', + [['--x', '3px']], + 'false_value'); + test_if_with_custom_properties(`if(style(--length >= 30px): true_value; + else: false_value)`, + [['--length', 'attr(data-foo type(<length>))']], + 'true_value'); + + // style() queries with range syntax in the condition, double range + test_if_with_custom_properties('if(style(10px <= 10px < 11px): true_value; else: false_value)', [], 'true_value'); + test_if_with_custom_properties('if(style(3 < --x <= 5): true_value; else: false_value)', + [['--x', '5']], + 'true_value'); + test_if_with_custom_properties('if(style(--x >= --y > --z): true_value; else: false_value)', + [['--x', '3'], ['--y', '3'], ['--z', '3']], + 'false_value'); + test_if_with_custom_properties('if(style(--x >= --y > --z): true_value; else: false_value)', + [['--x', '3'], ['--y', '3'], ['--z', '1']], + 'true_value'); + // media() queries in the condition test_if(`if(media(max-width: 1px): true_value; else: false_value)`, diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-function-container-query-invalidation.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-function-container-query-invalidation.html new file mode 100644 index 00000000000..c0d6d913af0 --- /dev/null +++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-function-container-query-invalidation.html @@ -0,0 +1,92 @@ +<!DOCTYPE html> +<title>CSS Values and Units Test: sibling-index() and sibling-count() changes in container queries</title> +<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting"> +<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#container-features"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + @property --length { + syntax: "<length>"; + initial-value: 0px; + inherits: false; + } + .container { container-type: inline-size; } + #c1 { + width: 100px; + --length: 100px; + } + #c2 { + width: 400px; + --length: 600px; + } + span { + --match-100: no; + --match-600: no; + } + @container (width = calc(100px * sibling-index())) { + span { background-color: green; } + } + @container (width = calc(200px * sibling-count())) { + span { color: lime; } + } + @container style(--length: calc(100px * sibling-index())) { + span { --match-100: yes; } + } + @container style(--length: calc(300px * sibling-count())) { + span { --match-600: yes; } + } +</style> +<div style="color:black"> + <div id="rm1"></div> + <div id="rm2"></div> + <div id="c1" class="container"> + <span id="t1"></span> + </div> + <div id="c2" class="container"> + <span id="t2"></span> + </div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(t1).backgroundColor, "rgba(0, 0, 0, 0)"); + assert_equals(getComputedStyle(t1).color, "rgb(0, 0, 0)"); + }, "sibling-index() in @container width query initially not matching"); + + test(() => { + assert_equals(getComputedStyle(t1).backgroundColor, "rgba(0, 0, 0, 0)"); + assert_equals(getComputedStyle(t1).color, "rgb(0, 0, 0)"); + }, "sibling-count() in @container width query initially not matching"); + + test(() => { + assert_equals(getComputedStyle(t1).getPropertyValue("--match-100"), "no"); + assert_equals(getComputedStyle(t1).getPropertyValue("--match-600"), "no"); + }, "sibling-index() in @container style() query initially not matching"); + + test(() => { + assert_equals(getComputedStyle(t2).getPropertyValue("--match-100"), "no"); + assert_equals(getComputedStyle(t2).getPropertyValue("--match-600"), "no"); + }, "sibling-count() in @container style() query initially not matching"); + + rm1.remove(); + rm2.remove(); + + test(() => { + assert_equals(getComputedStyle(t1).backgroundColor, "rgb(0, 128, 0)"); + assert_equals(getComputedStyle(t1).color, "rgb(0, 0, 0)"); + }, "sibling-index() in @container width query matching after removal"); + + test(() => { + assert_equals(getComputedStyle(t2).backgroundColor, "rgba(0, 0, 0, 0)"); + assert_equals(getComputedStyle(t2).color, "rgb(0, 255, 0)"); + }, "sibling-count() in @container width query matching after removal"); + + test(() => { + assert_equals(getComputedStyle(t1).getPropertyValue("--match-100"), "yes"); + assert_equals(getComputedStyle(t1).getPropertyValue("--match-600"), "no"); + }, "sibling-index() in @container style() query matching after removal"); + + test(() => { + assert_equals(getComputedStyle(t2).getPropertyValue("--match-100"), "no"); + assert_equals(getComputedStyle(t2).getPropertyValue("--match-600"), "yes"); + }, "sibling-count() in @container style() query matching after removal"); +</script> diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html index 77af5434a1c..ac2ed1a8af1 100644 --- a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html +++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html @@ -13,6 +13,7 @@ @property --length { syntax: "<length>"; initial-value: 0px; inherits: false; } @property --length-percentage { syntax: "<length-percentage>"; initial-value: 0px; inherits: false; } @property --color { syntax: "<color>"; initial-value: black; inherits: false; } + @property --list { syntax: "<integer>+"; initial-value: 0; inherits: false; } @keyframes --anim { from { @@ -25,6 +26,7 @@ --length: calc(sibling-index() * 7px); --length-percentage: calc((sibling-index() * 8px) + (sibling-count() * 5%)); --color: color(srgb 0 calc(0.2 * sibling-index()) 0); + --list: 13 sibling-index(); } to { --time: 13s; @@ -36,6 +38,7 @@ --length: 13px; --length-percentage: calc(13px + 7%); --color: red; + --list: 29 sibling-index(); } } #target { @@ -75,6 +78,9 @@ test(() => { assert_equals(getComputedStyle(target).getPropertyValue("--color"), "color(srgb 0 0.6 0)"); }, "Initially, the sibling-index() is 3 for --color"); + test(() => { + assert_equals(getComputedStyle(target).getPropertyValue("--list"), "13 3"); + }, "Initially, the sibling-index() is 3 for --list"); rm.remove(); @@ -105,5 +111,8 @@ test(() => { assert_equals(getComputedStyle(target).getPropertyValue("--color"), "color(srgb 0 0.4 0)"); }, "Removing a preceding sibling of #target reduces the sibling-index() for --color"); + test(() => { + assert_equals(getComputedStyle(target).getPropertyValue("--list"), "13 2"); + }, "Removing a preceding sibling of #target reduces the sibling-index() for --list"); </script> diff --git a/tests/wpt/tests/css/css-view-transitions/auto-name-from-id.html b/tests/wpt/tests/css/css-view-transitions/auto-name-from-id.html index d3430c93a1d..20080d7623a 100644 --- a/tests/wpt/tests/css/css-view-transitions/auto-name-from-id.html +++ b/tests/wpt/tests/css/css-view-transitions/auto-name-from-id.html @@ -34,6 +34,12 @@ main.switch #item1 { left: 100px; } +/* Make test fail if ID matches */ +::view-transition-group(item1), +::view-transition-group(item2) { + border: 2px solid red; +} + html::view-transition { background: rebeccapurple; } diff --git a/tests/wpt/tests/css/css-view-transitions/auto-name-get-animations.html b/tests/wpt/tests/css/css-view-transitions/auto-name-get-animations.html index 0442255542c..b684349a5f9 100644 --- a/tests/wpt/tests/css/css-view-transitions/auto-name-get-animations.html +++ b/tests/wpt/tests/css/css-view-transitions/auto-name-get-animations.html @@ -1,6 +1,6 @@ <!DOCTYPE html> <html > -<title>View transitions: generated names should not be visible from script</title> +<title>View transitions: generated names should be prefixed with -ua- in script</title> <link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -57,12 +57,20 @@ main.switch .item1 { }).ready; const animations = document.documentElement.getAnimations({subtree: true}); const pseudos = Array.from(new Set(animations.map(a => a.effect.pseudoElement))); + const item1GeneratedName = pseudos[0].replace("::view-transition-group(", "").slice(0, -1); + const item2GeneratedName = pseudos[3].replace("::view-transition-group(", "").slice(0, -1); + assert_true(item1GeneratedName.startsWith("-ua-"), "Item 1 generated name starts with -ua-"); + assert_true(item2GeneratedName.startsWith("-ua-"), "Item 2 generated name starts with -ua-"); assert_array_equals(pseudos, [ - "::view-transition-group(match-element)", - "::view-transition-new(match-element)", - "::view-transition-old(match-element)"]); - }, "Generated view-transition-names should not be reflected in script"); + `::view-transition-group(${item1GeneratedName})`, + `::view-transition-old(${item1GeneratedName})`, + `::view-transition-new(${item1GeneratedName})`, + `::view-transition-group(${item2GeneratedName})`, + `::view-transition-old(${item2GeneratedName})`, + `::view-transition-new(${item2GeneratedName})` + ], "Generated names should start with -ua- and pseudo-elements should be in tree order"); + }, "Generated view-transition-names should be prefixed with -ua- in script"); </script> </body>
\ No newline at end of file diff --git a/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter-ref.html b/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter-ref.html new file mode 100644 index 00000000000..9dd26f2c3b1 --- /dev/null +++ b/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter-ref.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>View transitions: inline child with filter (ref)</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="author" href="mailto:mattwoodrow@apple.com"> + +<style> +body { margin : 0; } +#target { + width: 100px; + height: 100px; + background-color: grey; + overflow-clip-margin: 40px; + contain: paint; + view-transition-name: target; +} + +#child { + position: relative; + left: 100px; + top: 100px; + color: lightgreen; + background-color: darkgreen; + filter: blur(30px); + transform: translateZ(0px); +} +</style> + +<div id="target"> + <span id="child">INLINEBOX</span> +</div> diff --git a/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter.html b/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter.html new file mode 100644 index 00000000000..36ba9803e1e --- /dev/null +++ b/tests/wpt/tests/css/css-view-transitions/inline-child-with-composited-filter.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>View transitions: inline child with filter</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="author" href="mailto:mattwoodrow@apple.com"> +<link rel="match" href="inline-child-with-filter-ref.html"> +<meta name=fuzzy content="maxDifference=0-2;totalPixels=0-2400"> +<script src="/common/reftest-wait.js"></script> + +<style> +body { margin : 0; } +#target { + width: 100px; + height: 100px; + background-color: grey; + overflow-clip-margin: 40px; + contain: paint; + view-transition-name: target; +} + +#child { + position: relative; + left: 100px; + top: 100px; + color: lightgreen; + background-color: darkgreen; + filter: blur(30px); + transform: translateZ(0px); +} + +html::view-transition-group(root) { animation-duration: 300s; } +html::view-transition-old(target) { + animation: unset; + opacity: 1; +} +html::view-transition-new(target) { + animation: unset; + opacity: 0; +} +</style> + +<div id="target"> + <span id="child">INLINEBOX</span> +</div> + +<script> +failIfNot(document.startViewTransition, "Missing document.startViewTransition"); + +async function runTest() { + let transition = document.startViewTransition(async () => { + document.getElementById("target").remove(); + }); + transition.ready.then(() => requestAnimationFrame(takeScreenshot)); +} +onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest)); +</script> diff --git a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html index 31f8449ff63..77fb0570966 100644 --- a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html +++ b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html @@ -4,7 +4,7 @@ <link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/"> <link rel="author" href="mailto:khushalsagar@chromium.org"> <link rel="match" href="inline-with-offset-from-containing-block-ref.html"> -<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1500"> +<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1633"> <script src="/common/reftest-wait.js"></script> <script src="/common/rendering-utils.js"></script> diff --git a/tests/wpt/tests/css/css-view-transitions/navigation/resources/auto-name-from-id.html b/tests/wpt/tests/css/css-view-transitions/navigation/resources/auto-name-from-id.html index 71ea52a273e..dc2cf8fd29b 100644 --- a/tests/wpt/tests/css/css-view-transitions/navigation/resources/auto-name-from-id.html +++ b/tests/wpt/tests/css/css-view-transitions/navigation/resources/auto-name-from-id.html @@ -29,6 +29,11 @@ html::view-transition-group(*) { animation-timing-function: steps(2, start); } +/* Make test fail if ID matches */ +::view-transition-group(green) { + border: 2px solid red; +} + #green { background: green; width: 100px; diff --git a/tests/wpt/tests/css/css-view-transitions/nested/nested-exit.tentative.html b/tests/wpt/tests/css/css-view-transitions/nested/nested-exit.tentative.html index 83570762061..847058be2b4 100644 --- a/tests/wpt/tests/css/css-view-transitions/nested/nested-exit.tentative.html +++ b/tests/wpt/tests/css/css-view-transitions/nested/nested-exit.tentative.html @@ -15,6 +15,10 @@ animation-play-state: paused; } + ::view-transition-group-children(*) { + background: inherit; + } + ::view-transition-group(parent) { background: green; visibility: hidden; diff --git a/tests/wpt/tests/css/css-view-transitions/nested/resources/compute-common.css b/tests/wpt/tests/css/css-view-transitions/nested/resources/compute-common.css index 20337ccce5f..d8f46179b40 100644 --- a/tests/wpt/tests/css/css-view-transitions/nested/resources/compute-common.css +++ b/tests/wpt/tests/css/css-view-transitions/nested/resources/compute-common.css @@ -57,6 +57,9 @@ html.no-match::view-transition { ::view-transition-group(green) { background: green; } +::view-transition-group-children(*) { + background: inherit; +} ::view-transition-group(test) { background: inherit; } diff --git a/tests/wpt/tests/css/css-view-transitions/nested/rounded-border-clipper.html b/tests/wpt/tests/css/css-view-transitions/nested/rounded-border-clipper.html index 239bcdd791d..098e5566585 100644 --- a/tests/wpt/tests/css/css-view-transitions/nested/rounded-border-clipper.html +++ b/tests/wpt/tests/css/css-view-transitions/nested/rounded-border-clipper.html @@ -33,6 +33,9 @@ ::view-transition-group(clipper) { animation-play-state: paused; +} + +::view-transition-group-children(clipper) { overflow: clip; border-radius: 20px; } diff --git a/tests/wpt/tests/css/css-view-transitions/new-content-captures-different-size.html b/tests/wpt/tests/css/css-view-transitions/new-content-captures-different-size.html index eeb7347981d..0a754c651ff 100644 --- a/tests/wpt/tests/css/css-view-transitions/new-content-captures-different-size.html +++ b/tests/wpt/tests/css/css-view-transitions/new-content-captures-different-size.html @@ -5,7 +5,7 @@ <link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/"> <link rel="author" href="mailto:vmpstr@chromium.org"> <link rel="match" href="new-content-captures-different-size-ref.html"> -<meta name=fuzzy content="maxDifference=0-100; totalPixels=0-15000"> +<meta name=fuzzy content="maxDifference=0-100; totalPixels=0-15393"> <script src="/common/reftest-wait.js"></script> <style> html { diff --git a/tests/wpt/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html b/tests/wpt/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html index f9fe2022258..14717728b15 100644 --- a/tests/wpt/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html +++ b/tests/wpt/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html @@ -17,7 +17,10 @@ view-transition-class: cls; } -:root::view-transition-group(*) { +:root::view-transition-group(*), +:root::view-transition-image-pair(*), +:root::view-transition-new(*), +:root::view-transition-old(*) { animation-play-state: paused; } diff --git a/tests/wpt/tests/css/css-view-transitions/scoped/crashtests/participating-scope.html b/tests/wpt/tests/css/css-view-transitions/scoped/crashtests/participating-scope.html new file mode 100644 index 00000000000..26979e58458 --- /dev/null +++ b/tests/wpt/tests/css/css-view-transitions/scoped/crashtests/participating-scope.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html class="test-wait"> +<head> +<style> +body { margin: 5px; } +#scope { contain: strict; position: relative; z-index: 0; + width: 150px; height: 100px; border: 5px solid #ccc; + view-transition-name: container; } +.item { width: 6rem; height: 4rem; margin: 10px; background: #def; + view-transition-name: a1; contain: strict; } +::view-transition-group(*), +::view-transition-old(*), +::view-transition-new(*) { animation: unset; } +</style> +</head> +<body> +<div id="scope"><div class="item"></div></div> +<script> +onload = async () => { + await scope.startViewTransition().finished; + document.documentElement.classList.remove('test-wait'); +} +</script> +</body> +</html> diff --git a/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope-ref.html b/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope-ref.html index 804741cd6db..951c0928687 100644 --- a/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope-ref.html +++ b/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope-ref.html @@ -4,7 +4,7 @@ <style> .box { position: relative; contain: strict; } -#scopeA { background: #ddd; +#scopeA { background: #ccc; left: 0; top: 0; width: 300px; height: 300px; } #partA { background: #4af; left: 30px; top: 30px; width: 240px; height: 240px; } diff --git a/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope.html b/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope.html index 9fff44e5e73..b9cc25c3338 100644 --- a/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope.html +++ b/tests/wpt/tests/css/css-view-transitions/scoped/nested-scope.html @@ -36,11 +36,22 @@ failIfNot(scopeA.startViewTransition, "Missing element.startViewTransition"); +// This test runs simultaneous transitions on two scopes, one inside the other. +// It verifies that the inner and outer participants are both visible while both +// transitions are in progress. (This entails rendering the inner transition +// through the ::view-transition-new for the outer participant.) async function runTest() { await waitForCompositorReady(); await scopeB.startViewTransition().ready; + + // Untag partB to avoid a collision when the outer transition looks for its + // participants. (We can stop doing this once we have contain: view-transition + // or similar.) partB.classList.remove("tr"); - await scopeA.startViewTransition().ready; + + await scopeA.startViewTransition(() => { + scopeA.style.background = "#ccc"; + }).ready; requestAnimationFrame(takeScreenshot); } onload = () => runTest(); diff --git a/tests/wpt/tests/css/css-viewport/zoom/height.html b/tests/wpt/tests/css/css-viewport/zoom/height.html new file mode 100644 index 00000000000..f608765bcf1 --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/height.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>height:inherit applies zoom</title> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<link rel="match" href="green-square-100px.html"> +<style> + div > div { + background-color: green; + } +</style> +<div style="height:50px"> + <div style="zoom:2; width:50px; height:inherit;"></div> +</div> diff --git a/tests/wpt/tests/css/css-viewport/zoom/inherited-length.html b/tests/wpt/tests/css/css-viewport/zoom/inherited-length.html index d83111a4352..571b533d5d6 100644 --- a/tests/wpt/tests/css/css-viewport/zoom/inherited-length.html +++ b/tests/wpt/tests/css/css-viewport/zoom/inherited-length.html @@ -10,6 +10,6 @@ div { background-color: green; } </style> -<div style="width: 100px; height: 100px;"> - <div style="zoom: 2; width: inherit;"></div> +<div style="width: 50px; height: 50px;"> + <div style="zoom: 2; width: inherit; height: inherit;"></div> </div> diff --git a/tests/wpt/tests/css/css-viewport/zoom/length-implicit-and-explicit-inheritance.html b/tests/wpt/tests/css/css-viewport/zoom/length-implicit-and-explicit-inheritance.html new file mode 100644 index 00000000000..003c7b61c09 --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/length-implicit-and-explicit-inheritance.html @@ -0,0 +1,38 @@ +<!doctype html> +<meta charset="utf-8"> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<link rel="help" href="https://drafts.csswg.org/css-viewport/#zoom-property"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div style="zoom: 2"> + <div style="zoom: 2" id="parent"> + <!-- effective zoom of 8, inherited zoom (4) times specified zoom (2) --> + <div style="zoom: 2" id="target"></div> + </div> +</div> +<script> + const kTestCases = [ + // Explicitly inherited reset properties. + ["width", "100px", "inherit", "100px"], + ["height", "100px", "inherit", "100px"], + // Explicitly inherited properties. + ["word-spacing", "100px", "inherit", "100px"], + ["word-spacing", "100px", "unset", "100px"], + // Implicitly inherited properties. + ["word-spacing", "100px", "", "100px"], + ]; + + const parent = document.getElementById("parent"); + const target = document.getElementById("target"); + for (const [prop, parentValue, childValue, expected] of kTestCases) { + test(function(t) { + parent.style[prop] = parentValue; + target.style[prop] = childValue; + t.add_cleanup(function() { + parent.style[prop] = target.style[prop] = ""; + }); + assert_equals(getComputedStyle(target).getPropertyValue(prop), expected); + }, `${prop}: ${childValue} from ${parentValue}`); + } +</script> diff --git a/tests/wpt/tests/css/css-viewport/zoom/max-height.html b/tests/wpt/tests/css/css-viewport/zoom/max-height.html new file mode 100644 index 00000000000..6a0dcd826e2 --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/max-height.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>max-height:inherit applies zoom</title> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<link rel="match" href="green-square-100px.html"> +<style> + div > div { + background-color: green; + } +</style> +<div style="max-height:50px"> + <div style="zoom:2; width:50px; height:200px; max-height:inherit;"></div> +</div> diff --git a/tests/wpt/tests/css/css-viewport/zoom/max-width.html b/tests/wpt/tests/css/css-viewport/zoom/max-width.html new file mode 100644 index 00000000000..b6d4139e30a --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/max-width.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>max-width:inherit applies zoom</title> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<link rel="match" href="green-square-100px.html"> +<style> + div > div { + background-color: green; + } +</style> +<div style="max-width:50px"> + <div style="zoom:2; max-width:inherit; height:50px; width:300px;"></div> +</div> diff --git a/tests/wpt/tests/css/css-viewport/zoom/min-height.html b/tests/wpt/tests/css/css-viewport/zoom/min-height.html new file mode 100644 index 00000000000..31a47d92b21 --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/min-height.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>min-height:inherit applies zoom</title> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<link rel="match" href="green-square-100px.html"> +<style> + div > div { + background-color: green; + } +</style> +<div style="min-height:50px"> + <div style="zoom:2; width:50px; min-height:inherit;"></div> +</div> diff --git a/tests/wpt/tests/css/css-viewport/zoom/min-width.html b/tests/wpt/tests/css/css-viewport/zoom/min-width.html new file mode 100644 index 00000000000..bd1cda23d3a --- /dev/null +++ b/tests/wpt/tests/css/css-viewport/zoom/min-width.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>min-width:inherit applies zoom</title> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<link rel="match" href="green-square-100px.html"> +<style> + div > div { + background-color: green; + } +</style> +<div style="min-width:50px"> + <div style="zoom:2; min-width:inherit; height:50px; width:0px"></div> +</div> diff --git a/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001-ref.html b/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001-ref.html new file mode 100644 index 00000000000..f50121ef16d --- /dev/null +++ b/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001-ref.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset=utf-8> + +<title>CSS writing-mode reference</title> + +<style> +table { margin: 10px; } +td { background: green; padding: 10px 20px 30px 40px; } +div { width: 20px; height: 40px; background: blue; } +</style> + +<p>All five green squares should look the same, with a blue rectangle towards the upper right.</p> + +<table> + <td><div></div></td> +</table> + +<table> + <td><div></div></td> +</table> + +<table> + <td><div></div></td> +</table> + +<table> + <td><div></div></td> +</table> + +<table> + <td><div></div></td> +</table> diff --git a/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001.html b/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001.html new file mode 100644 index 00000000000..12e996ac902 --- /dev/null +++ b/tests/wpt/tests/css/css-writing-modes/orthogonal-cell-001.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset=utf-8> + +<title>CSS writing-mode test: orthogonal table cells</title> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1959395"> +<link rel="match" href="orthogonal-cell-001-ref.html"> + +<style> +table { margin: 10px; } +td { background: green; padding: 10px 20px 30px 40px; } +div { width: 20px; height: 40px; background: blue; } +.htb { writing-mode: horizontal-tb; } +.vlr { writing-mode: vertical-lr; } +.vrl { writing-mode: vertical-rl; } +</style> + +<p>All five green squares should look the same, with a blue rectangle towards the upper right.</p> + +<table> + <td><div></div></td> +</table> + +<!-- The different writing modes should not disrupt the table cell/row sizing. --> +<table class=htb> + <td class=vlr><div></div></td> +</table> + +<table class=htb> + <td class=vrl><div></div></td> +</table> + +<table class=vlr> + <td class=htb><div></div></td> +</table> + +<table class=vrl> + <td class=htb><div></div></td> +</table> diff --git a/tests/wpt/tests/css/motion/animation/offset-path-interpolation-008.html b/tests/wpt/tests/css/motion/animation/offset-path-interpolation-008.html index 5fb7c7c333c..ff7d4a108c7 100644 --- a/tests/wpt/tests/css/motion/animation/offset-path-interpolation-008.html +++ b/tests/wpt/tests/css/motion/animation/offset-path-interpolation-008.html @@ -132,15 +132,15 @@ test_interpolation({ property: 'offset-path', - from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', - to: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px cw rotate 270deg small, arc to 25% 20px of 10px 5px small cw)' + from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', + to: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px 20px cw rotate 270deg small, arc to 25% 20px of 10px 5px small cw)' }, [ {at: -0.3, expect: 'shape(from 2% 2px, arc to 18% -12px of 7px 17px ccw small, arc by 12% -2px of 33px 33px rotate -42deg cw large , arc to 25% 20px of 10px 5px ccw small)'}, - {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)'}, + {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)'}, {at: 0.3, expect: 'shape(from 8% 8px, arc to 12% -18px of 13px 23px ccw small, arc by 18% -8px of 27px 27px rotate 102deg cw large, arc to 25% 20px of 10px 5px cw small )'}, - {at: 0.5, expect: 'shape(from 10% 10px, arc to 10% -20px of 15px 25px ccw small, arc by 20% -10px of 25px rotate 150deg cw large, arc to 25% 20px of 10px 5px cw small)'}, - {at: 1, expect: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px rotate 270deg cw small, arc to 25% 20px of 10px 5px cw small)'}, - {at: 1.5, expect: 'shape(from 20% 20px, arc to 0% -30px of 25px 35px ccw small, arc by 30% -20px of 15px rotate 390deg cw small, arc to 25% 20px of 10px 5px cw small)'}, + {at: 0.5, expect: 'shape(from 10% 10px, arc to 10% -20px of 15px 25px ccw small, arc by 20% -10px of 25px 25px rotate 150deg cw large, arc to 25% 20px of 10px 5px cw small)'}, + {at: 1, expect: 'shape(from 15% 15px, arc to 5% -25px of 20px 30px, arc by 25% -15px of 20px 20px rotate 270deg cw small, arc to 25% 20px of 10px 5px cw small)'}, + {at: 1.5, expect: 'shape(from 20% 20px, arc to 0% -30px of 25px 35px ccw small, arc by 30% -20px of 15px 15px rotate 390deg cw small, arc to 25% 20px of 10px 5px cw small)'}, ]); test_interpolation({ @@ -235,28 +235,28 @@ test_interpolation({ property: 'offset-path', - from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', + from: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)', to: 'path("M 15 15 A 20,30 0 0,0 5,-25 a 20,20 270 0,1 25,-15 A 10,5 0 0,0 25 20")', }, [ - {at: -0.3, expect: 'shape(from calc(6.5% - 4.5px) 2px, arc to calc(19.5% - 1.5px) -12px of 7px 17px, arc by calc(19.5% - 7.5px) -2px of 33px cw large rotate -42deg, arc to calc(32.5% - 7.5px) 20px of 10px 5px)'}, - {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px cw rotate 30deg large, arc to 25% 20px of 10px 5px small)'}, - {at: 0.3, expect: 'shape(from calc(3.5% + 4.5px) 8px, arc to calc(10.5% + 1.5px) -18px of 13px 23px, arc by calc(10.5% + 7.5px) -8px of 27px cw large rotate 102deg, arc to calc(17.5% + 7.5px) 20px of 10px 5px)'}, - {at: 0.5, expect: 'shape(from calc(2.5% + 7.5px) 10px, arc to calc(7.5% + 2.5px) -20px of 15px 25px, arc by calc(7.5% + 12.5px) -10px of 25px cw large rotate 150deg, arc to calc(12.5% + 12.5px) 20px of 10px 5px)'}, - {at: 1, expect: 'shape(from calc(0% + 15px) 15px, arc to calc(0% + 5px) -25px of 20px 30px, arc by calc(0% + 25px) -15px of 20px cw rotate 270deg, arc to calc(0% + 25px) 20px of 10px 5px)'}, - {at: 1.5, expect: 'shape(from calc(-2.5% + 22.5px) 20px, arc to calc(-7.5% + 7.5px) -30px of 25px 35px, arc by calc(-7.5% + 37.5px) -20px of 15px cw rotate 390deg, arc to calc(-12.5% + 37.5px) 20px of 10px 5px)'}, + {at: -0.3, expect: 'shape(from calc(6.5% - 4.5px) 2px, arc to calc(19.5% - 1.5px) -12px of 7px 17px, arc by calc(19.5% - 7.5px) -2px of 33px 33px cw large rotate -42deg, arc to calc(32.5% - 7.5px) 20px of 10px 5px)'}, + {at: 0, expect: 'shape(from 5% 5px, arc to 15% -15px of 10px 20px, arc by 15% -5px of 30px 30px cw large rotate 30deg, arc to 25% 20px of 10px 5px)'}, + {at: 0.3, expect: 'shape(from calc(3.5% + 4.5px) 8px, arc to calc(10.5% + 1.5px) -18px of 13px 23px, arc by calc(10.5% + 7.5px) -8px of 27px 27px cw large rotate 102deg, arc to calc(17.5% + 7.5px) 20px of 10px 5px)'}, + {at: 0.5, expect: 'shape(from calc(2.5% + 7.5px) 10px, arc to calc(7.5% + 2.5px) -20px of 15px 25px, arc by calc(7.5% + 12.5px) -10px of 25px 25px cw large rotate 150deg, arc to calc(12.5% + 12.5px) 20px of 10px 5px)'}, + {at: 1, expect: 'shape(from calc(0% + 15px) 15px, arc to calc(0% + 5px) -25px of 20px 30px, arc by calc(0% + 25px) -15px of 20px 20px cw rotate 270deg, arc to calc(0% + 25px) 20px of 10px 5px)'}, + {at: 1.5, expect: 'shape(from calc(-2.5% + 22.5px) 20px, arc to calc(-7.5% + 7.5px) -30px of 25px 35px, arc by calc(-7.5% + 37.5px) -20px of 15px 15px cw rotate 390deg, arc to calc(-12.5% + 37.5px) 20px of 10px 5px)'}, ]); test_interpolation({ property: 'offset-path', from: 'path("M 5 5 A 10,20 0 0,0 15,-15 a 30,30 30 1,1 15,-5 A 10,5 0 0,0 25 20")', - to: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px cw rotate 270deg small, arc to 25px 20px of 10px 5px small cw)' + to: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px 20px cw rotate 270deg small, arc to 25px 20px of 10px 5px small cw)' }, [ - {at: -0.3, expect: 'shape(from 2px 2px, arc to 18px -12px of 7px 17px ccw small, arc by 12px -2px of 33px 33px rotate -42deg cw large, arc to 25px 20px of 10px 5px ccw small)'}, - {at: 0, expect: 'shape(from 5px 5px, arc to 15px -15px of 10px 20px, arc by 15px -5px of 30px cw rotate 30deg large, arc to 25px 20px of 10px 5px small)'}, + {at: -0.3, expect: 'shape(from 2px 2px, arc to 18px -12px of 7px 17px ccw small, arc by 12px -2px of 33px 33px rotate -42deg cw large, arc to 25px 20px of 10px 5px ccw small)'}, + {at: 0, expect: 'shape(from 5px 5px, arc to 15px -15px of 10px 20px, arc by 15px -5px of 30px 30px cw rotate 30deg large, arc to 25px 20px of 10px 5px small)'}, {at: 0.3, expect: 'shape(from 8px 8px, arc to 12px -18px of 13px 23px ccw small, arc by 18px -8px of 27px 27px rotate 102deg cw large, arc to 25px 20px of 10px 5px cw small)'}, - {at: 0.5, expect: 'shape(from 10px 10px, arc to 10px -20px of 15px 25px ccw small, arc by 20px -10px of 25px rotate 150deg cw large, arc to 25px 20px of 10px 5px cw small)'}, - {at: 1, expect: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px rotate 270deg cw small, arc to 25px 20px of 10px 5px cw small)'}, - {at: 1.5, expect: 'shape(from 20px 20px, arc to 0px -30px of 25px 35px ccw small, arc by 30px -20px of 15px rotate 390deg cw small, arc to 25px 20px of 10px 5px cw small)'}, + {at: 0.5, expect: 'shape(from 10px 10px, arc to 10px -20px of 15px 25px ccw small, arc by 20px -10px of 25px 25px rotate 150deg cw large, arc to 25px 20px of 10px 5px cw small)'}, + {at: 1, expect: 'shape(from 15px 15px, arc to 5px -25px of 20px 30px, arc by 25px -15px of 20px 20px rotate 270deg cw small, arc to 25px 20px of 10px 5px cw small)'}, + {at: 1.5, expect: 'shape(from 20px 20px, arc to 0px -30px of 25px 35px ccw small, arc by 30px -20px of 15px 15px rotate 390deg cw small, arc to 25px 20px of 10px 5px cw small)'}, ]); </script> diff --git a/tests/wpt/tests/css/motion/parsing/offset-path-shape-computed.html b/tests/wpt/tests/css/motion/parsing/offset-path-shape-computed.html index c9ecc3acb06..6ced1ad395a 100644 --- a/tests/wpt/tests/css/motion/parsing/offset-path-shape-computed.html +++ b/tests/wpt/tests/css/motion/parsing/offset-path-shape-computed.html @@ -27,8 +27,8 @@ test_computed_value("offset-path", "shape(from 10px 10px, curve to 50px 20px wit test_computed_value("offset-path", "shape(from 10px 10px, curve to 50px 20px with 10rem 1px / 20% 1em)", "shape(from 10px 10px, curve to 50px 20px with 160px 1px / 20% 16px)"); test_computed_value("offset-path", "shape(from 10px 10px, smooth to 50px 20px with 10rem 1%)", "shape(from 10px 10px, smooth to 50px 20px with 160px 1%)"); test_computed_value("offset-path", "shape(from 10px 10px, smooth to 50px 3pt)", "shape(from 10px 10px, smooth to 50px 4px)"); -test_computed_value("offset-path", "shape(from 10px 10px, arc to 50px 3pt of 10px 10px)", "shape(from 10px 10px, arc to 50px 4px of 10px)"); -test_computed_value("offset-path", "shape(from 10px 10px, arc to 50px 3pt of 10px 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 4px of 10px)"); +test_computed_value("offset-path", "shape(from 10px 10px, arc to 50px 3pt of 10px 10px)", "shape(from 10px 10px, arc to 50px 4px of 10px 10px)"); +test_computed_value("offset-path", "shape(from 10px 10px, arc to 50px 3pt of 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 4px of 10px)"); test_computed_value("offset-path", "shape(from 10% 1rem, arc to 50px 3pt of 20% cw large rotate 25deg)", "shape(from 10% 16px, arc to 50px 4px of 20% cw large rotate 25deg)"); </script> </body> diff --git a/tests/wpt/tests/css/motion/parsing/offset-path-shape-parsing.html b/tests/wpt/tests/css/motion/parsing/offset-path-shape-parsing.html index 013cea2c821..4a3d9f16915 100644 --- a/tests/wpt/tests/css/motion/parsing/offset-path-shape-parsing.html +++ b/tests/wpt/tests/css/motion/parsing/offset-path-shape-parsing.html @@ -28,8 +28,8 @@ test_valid_value("offset-path", "shape(from 10px 10px, curve to 50px 20px with 1 test_valid_value("offset-path", "shape(from 10px 10px, curve by 50px 20px with 10rem 1px / 20vh 1ch)"); test_valid_value("offset-path", "shape(from 10px 10px, smooth to 50px 20px with 10rem 1%)"); test_valid_value("offset-path", "shape(from 10px 10px, smooth to 50px 1pt)"); -test_valid_value("offset-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)", "shape(from 10px 10px, arc to 50px 1pt of 10px)"); -test_valid_value("offset-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 1pt of 10px)"); +test_valid_value("offset-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)"); +test_valid_value("offset-path", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px small rotate 0deg)", "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)"); test_valid_value("offset-path", "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)", "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)"); test_valid_value("offset-path", "shape(evenodd from 0px 0px, line to 10px 10px)"); test_valid_value("offset-path", "shape(nonzero from 0px 0px, line to 10px 10px)", "shape(from 0px 0px, line to 10px 10px)"); diff --git a/tests/wpt/tests/css/visited-nested-ref.html b/tests/wpt/tests/css/selectors/visited-nested-ref.html index 22f4ecf0d7b..22f4ecf0d7b 100644 --- a/tests/wpt/tests/css/visited-nested-ref.html +++ b/tests/wpt/tests/css/selectors/visited-nested-ref.html diff --git a/tests/wpt/tests/css/visited-nested.html b/tests/wpt/tests/css/selectors/visited-nested.html index 57220446c86..57220446c86 100644 --- a/tests/wpt/tests/css/visited-nested.html +++ b/tests/wpt/tests/css/selectors/visited-nested.html diff --git a/tests/wpt/tests/domxpath/fn-id.html b/tests/wpt/tests/domxpath/fn-id.html new file mode 100644 index 00000000000..617ff7216d8 --- /dev/null +++ b/tests/wpt/tests/domxpath/fn-id.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-id"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// Test the id() function with various scenarios +function testIdFunction(expression, xmlString, expectedIds) { + let doc = (new DOMParser()).parseFromString(xmlString, 'text/xml'); + test(() => { + let result = doc.evaluate(expression, doc.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + assert_equals(result.resultType, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); + let actualIds = []; + for (let i = 0; i < result.snapshotLength; i++) { + actualIds.push(result.snapshotItem(i).getAttribute('id')); + } + actualIds.sort(); + expectedIds.sort(); + assert_array_equals(actualIds, expectedIds, `Expected IDs ${expectedIds}, got ${actualIds}`); + }, `${expression}: ${doc.documentElement.outerHTML}`); +} + +// Test single ID +testIdFunction('id("test1")', '<root><div id="test1">Match</div></root>', ['test1']); + +// Test multiple IDs in space-separated string +testIdFunction('id("test1 test2")', '<root><div id="test1">First</div><div id="test2">Second</div></root>', ['test1', 'test2']); + +// Test non-existent ID +testIdFunction('id("nonexistent")', '<root><div id="test1">No match</div></root>', []); + +// Test mixed case IDs (should be case-sensitive) +testIdFunction('id("Test1")', '<root><div id="test1">No match</div></root>', []); + +// Test multiple elements with same ID (should return all) +testIdFunction('id("duplicate")', '<root><div id="duplicate">First</div><div id="duplicate">Second</div></root>', ['duplicate', 'duplicate']); + +// Test IDs with special characters +testIdFunction('id("test-1")', '<root><div id="test-1">Match</div></root>', ['test-1']); + +// Test empty ID string +testIdFunction('id("")', '<root><div id="">Empty ID</div></root>', []); + +// Test whitespace in ID string +testIdFunction('id(" test1 ")', '<root><div id="test1">Match</div></root>', ['test1']); +</script> +</body> diff --git a/tests/wpt/tests/editing/crashtests/indent-outdent-after-closing-editable-dialog-element.html b/tests/wpt/tests/editing/crashtests/indent-outdent-after-closing-editable-dialog-element.html deleted file mode 100644 index 7f73de048d7..00000000000 --- a/tests/wpt/tests/editing/crashtests/indent-outdent-after-closing-editable-dialog-element.html +++ /dev/null @@ -1,31 +0,0 @@ -<html class="reftest-wait"> -<script> -var eventCount = 0; -document.addEventListener("DOMContentLoaded", () => { - const dialog = document.querySelector("dialog"); - const object = document.createElement("object"); - object.addEventListener("DOMSubtreeModified", () => { - dialog.show(); - dialog.focus(); - document.execCommand("selectAll"); - dialog.close(); - setTimeout(() => { - document.execCommand("selectAll"); - document.execCommand("strikeThrough"); - document.execCommand("indent"); - document.execCommand("outdent"); - eventCount--; - if (!eventCount) { - document.documentElement.removeAttribute("class"); - } - }); - eventCount++; - }); - object.setAttribute("role", "x"); // Run DOMSubtreeModified - object.setAttribute("role", "y"); // Run DOMSubtreeModified - document.execCommand("forwardDelete"); - document.execCommand("justifyRight"); -}) -</script> -<dialog id="a" contenteditable="true">a</dialog> -</html>
\ No newline at end of file diff --git a/tests/wpt/tests/editing/other/move-inserted-node-from-DOMNodeInserted-during-exec-command-insertHTML.html b/tests/wpt/tests/editing/other/move-inserted-node-from-DOMNodeInserted-during-exec-command-insertHTML.html deleted file mode 100644 index 41e012a62e9..00000000000 --- a/tests/wpt/tests/editing/other/move-inserted-node-from-DOMNodeInserted-during-exec-command-insertHTML.html +++ /dev/null @@ -1,27 +0,0 @@ -<!doctype html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<div contenteditable> -<p id="p1"><br></p> -<p id="p2"></p> -</div> -<script> -"use strict"; -let editor = document.querySelector("[contenteditable]"); -let p1 = document.getElementById("p1"); -let p2 = document.getElementById("p2"); -p1.addEventListener("DOMNodeInserted", event => { - if (event.target.localName === "i") { - p2.appendChild(event.target); - } -}); -document.getSelection().collapse(p1, 0); -document.execCommand("insertHTML", false, - "<b>bold1</b><i>italic1</i><b>bold2</b><i>italic2</i>"); -test(function () { - assert_in_array(p1.innerHTML, ["<b>bold1</b><b>bold2</b><br>", "<b>bold1</b><b>bold2</b>"]); -}, "First <p> element should have only <b> elements"); -test(function () { - assert_equals(p2.innerHTML, "<i>italic1</i><i>italic2</i>"); -}, "Second <p> element should have only <i> elements"); -</script>
\ No newline at end of file diff --git a/tests/wpt/tests/fetch/content-encoding/br/bad-br-body.https.any.js b/tests/wpt/tests/fetch/content-encoding/br/bad-br-body.https.any.js index 43ea90a336c..af5df674da6 100644 --- a/tests/wpt/tests/fetch/content-encoding/br/bad-br-body.https.any.js +++ b/tests/wpt/tests/fetch/content-encoding/br/bad-br-body.https.any.js @@ -2,6 +2,11 @@ [ "arrayBuffer", + "blob", + "bytes", + "formData", + "json", + "text" ].forEach(method => { promise_test(t => { return fetch("resources/bad-br-body.py").then(res => { diff --git a/tests/wpt/tests/fetch/content-encoding/gzip/bad-gzip-body.any.js b/tests/wpt/tests/fetch/content-encoding/gzip/bad-gzip-body.any.js index 17bc1261a3f..77a183f408b 100644 --- a/tests/wpt/tests/fetch/content-encoding/gzip/bad-gzip-body.any.js +++ b/tests/wpt/tests/fetch/content-encoding/gzip/bad-gzip-body.any.js @@ -9,6 +9,7 @@ promise_test((test) => { [ "arrayBuffer", "blob", + "bytes", "formData", "json", "text" diff --git a/tests/wpt/tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.js b/tests/wpt/tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.js index 3f32e4dfba7..c59980c2c6f 100644 --- a/tests/wpt/tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.js +++ b/tests/wpt/tests/fetch/content-encoding/zstd/bad-zstd-body.https.any.js @@ -9,6 +9,7 @@ promise_test((test) => { [ "arrayBuffer", "blob", + "bytes", "formData", "json", "text" diff --git a/tests/wpt/tests/fetch/local-network-access/resources/fetch-private-http.html b/tests/wpt/tests/fetch/local-network-access/resources/fetch-private-http.html index e372d90b26a..517629b758e 100644 --- a/tests/wpt/tests/fetch/local-network-access/resources/fetch-private-http.html +++ b/tests/wpt/tests/fetch/local-network-access/resources/fetch-private-http.html @@ -23,8 +23,7 @@ Promise.resolve().then(async () => { }; const targetUrl = resolveTargetUrl(target); - // TODO(crbug.com/406991278): rename address space for LNA spec - fetch(targetUrl, {targetAddressSpace: 'private'}) + fetch(targetUrl, {targetAddressSpace: 'local'}) .then(async function(response) { const body = await response.text(); const message = { diff --git a/tests/wpt/tests/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html b/tests/wpt/tests/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html index 1d149d00cb3..c15a87ff7b9 100644 --- a/tests/wpt/tests/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html +++ b/tests/wpt/tests/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html @@ -25,8 +25,7 @@ Promise.resolve().then(async () => { }; const targetUrl = resolveTargetUrl(target); - // TODO(crbug.com/406991278): rename address space for LNA spec - fetch(targetUrl, {targetAddressSpace: 'private'}) + fetch(targetUrl, {targetAddressSpace: 'local'}) .then(async function(response) { const body = await response.text(); const message = { diff --git a/tests/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js b/tests/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js deleted file mode 100644 index dbae5193b5c..00000000000 --- a/tests/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js +++ /dev/null @@ -1,278 +0,0 @@ -// META: script=/common/utils.js -// META: script=resources/support.sub.js -// META: timeout=long -// -// Spec: https://wicg.github.io/private-network-access -// -// These tests verify that secure contexts can fetch non-secure subresources -// from more private address spaces, avoiding mixed context checks, as long as -// they specify a valid `targetAddressSpace` fetch option that matches the -// target server's address space. - -setup(() => { - // Making sure we are in a secure context, as expected. - assert_true(window.isSecureContext); -}); - -// Given `addressSpace`, returns the other three possible IP address spaces. -function otherAddressSpaces(addressSpace) { - switch (addressSpace) { - case "local": return ["unknown", "private", "public"]; - case "private": return ["unknown", "local", "public"]; - case "public": return ["unknown", "local", "private"]; - } -} - -// Generates tests of `targetAddressSpace` for the given (source, target) -// address space pair, expecting fetches to succeed iff `targetAddressSpace` is -// correct. -// -// Scenarios exercised: -// -// - cors mode: -// - missing targetAddressSpace option -// - incorrect targetAddressSpace option (x3, see `otherAddressSpaces()`) -// - failed preflight -// - success -// - success with PUT method (non-"simple" request) -// - no-cors mode: -// - success -// -function makeTests({ source, target }) { - const sourceServer = Server.get("https", source); - const targetServer = Server.get("http", target); - - const makeTest = ({ - fetchOptions, - targetBehavior, - name, - expected - }) => { - promise_test_parallel(t => fetchTest(t, { - source: { server: sourceServer }, - target: { - server: targetServer, - behavior: targetBehavior, - }, - fetchOptions, - expected, - }), `${sourceServer.name} to ${targetServer.name}: ${name}.`); - }; - - makeTest({ - name: "missing targetAddressSpace", - targetBehavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - expected: FetchTestResult.FAILURE, - }); - - const correctAddressSpace = targetServer.addressSpace; - - for (const targetAddressSpace of otherAddressSpaces(correctAddressSpace)) { - makeTest({ - name: `wrong targetAddressSpace "${targetAddressSpace}"`, - targetBehavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - fetchOptions: { targetAddressSpace }, - expected: FetchTestResult.FAILURE, - }); - } - - makeTest({ - name: "failed preflight", - targetBehavior: { - preflight: PreflightBehavior.failure(), - response: ResponseBehavior.allowCrossOrigin(), - }, - fetchOptions: { targetAddressSpace: correctAddressSpace }, - expected: FetchTestResult.FAILURE, - }); - - makeTest({ - name: "success", - targetBehavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - fetchOptions: { targetAddressSpace: correctAddressSpace }, - expected: FetchTestResult.SUCCESS, - }); - - makeTest({ - name: "PUT success", - targetBehavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - fetchOptions: { - targetAddressSpace: correctAddressSpace, - method: "PUT", - }, - expected: FetchTestResult.SUCCESS, - }); - - makeTest({ - name: "no-cors success", - targetBehavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - fetchOptions: { - targetAddressSpace: correctAddressSpace, - mode: "no-cors", - }, - expected: FetchTestResult.OPAQUE, - }); -} - -// Generates tests for the given (source, target) address space pair expecting -// that `targetAddressSpace` cannot be used to bypass mixed content. -// -// Scenarios exercised: -// -// - wrong `targetAddressSpace` (x3, see `otherAddressSpaces()`) -// - correct `targetAddressSpace` -// -function makeNoBypassTests({ source, target }) { - const sourceServer = Server.get("https", source); - const targetServer = Server.get("http", target); - - const prefix = `${sourceServer.name} to ${targetServer.name}: `; - - const correctAddressSpace = targetServer.addressSpace; - for (const targetAddressSpace of otherAddressSpaces(correctAddressSpace)) { - promise_test_parallel(t => fetchTest(t, { - source: { server: sourceServer }, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace }, - expected: FetchTestResult.FAILURE, - }), prefix + `wrong targetAddressSpace "${targetAddressSpace}".`); - } - - promise_test_parallel(t => fetchTest(t, { - source: { server: sourceServer }, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace: correctAddressSpace }, - expected: FetchTestResult.FAILURE, - }), prefix + 'not a private network request.'); -} - -// Source: local secure context. -// -// Fetches to the local and private address spaces cannot use -// `targetAddressSpace` to bypass mixed content, as they are not otherwise -// blocked by Private Network Access. - -makeNoBypassTests({ source: "local", target: "local" }); -makeNoBypassTests({ source: "local", target: "private" }); -makeNoBypassTests({ source: "local", target: "public" }); - -// Source: private secure context. -// -// Fetches to the local address space requires the right `targetAddressSpace` -// option, as well as a successful preflight response carrying a PNA-specific -// header. -// -// Fetches to the private address space cannot use `targetAddressSpace` to -// bypass mixed content, as they are not otherwise blocked by Private Network -// Access. - -makeTests({ source: "private", target: "local" }); - -makeNoBypassTests({ source: "private", target: "private" }); -makeNoBypassTests({ source: "private", target: "public" }); - -// Source: public secure context. -// -// Fetches to the local and private address spaces require the right -// `targetAddressSpace` option, as well as a successful preflight response -// carrying a PNA-specific header. - -makeTests({ source: "public", target: "local" }); -makeTests({ source: "public", target: "private" }); - -makeNoBypassTests({ source: "public", target: "public" }); - -// These tests verify that documents fetched from the `local` address space yet -// carrying the `treat-as-public-address` CSP directive are treated as if they -// had been fetched from the `public` address space. - -promise_test_parallel(t => fetchTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTP_LOCAL, - behavior: { - preflight: PreflightBehavior.optionalSuccess(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace: "private" }, - expected: FetchTestResult.FAILURE, -}), 'https-treat-as-public to http-local: wrong targetAddressSpace "private".'); - -promise_test_parallel(t => fetchTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTP_LOCAL, - behavior: { - preflight: PreflightBehavior.optionalSuccess(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace: "local" }, - expected: FetchTestResult.SUCCESS, -}), "https-treat-as-public to http-local: success."); - -promise_test_parallel(t => fetchTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTP_PRIVATE, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace: "local" }, - expected: FetchTestResult.FAILURE, -}), 'https-treat-as-public to http-private: wrong targetAddressSpace "local".'); - -promise_test_parallel(t => fetchTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTP_PRIVATE, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: { targetAddressSpace: "private" }, - expected: FetchTestResult.SUCCESS, -}), "https-treat-as-public to http-private: success."); diff --git a/tests/wpt/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js b/tests/wpt/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js deleted file mode 100644 index 6a2a624fc80..00000000000 --- a/tests/wpt/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js +++ /dev/null @@ -1,209 +0,0 @@ -// META: script=/common/subset-tests-by-key.js -// META: script=/common/dispatcher/dispatcher.js -// META: script=/common/utils.js -// META: script=resources/support.sub.js -// META: timeout=long -// META: variant=?include=from-local -// META: variant=?include=from-private -// META: variant=?include=from-public -// META: variant=?include=from-treat-as-public -// -// These tests verify that secure contexts can navigate to less-public address -// spaces via window.open to an existing window iff the target server responds -// affirmatively to preflight requests. - -setup(() => { - assert_true(window.isSecureContext); -}); - -// Source: secure local context. -// -// All fetches unaffected by Private Network Access. - -subsetTestByKey( - 'from-local', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_LOCAL}, - expected: NavigationTestResult.SUCCESS, - }), - 'local to local: no preflight required.'); - -subsetTestByKey( - 'from-local', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_PRIVATE}, - expected: NavigationTestResult.SUCCESS, - }), - 'local to private: no preflight required.'); - -subsetTestByKey( - 'from-local', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_PUBLIC}, - expected: NavigationTestResult.SUCCESS, - }), - 'local to public: no preflight required.'); - -// Generates tests of preflight behavior for a single (source, target) pair. -// -// Scenarios: -// -// - preflight response has non-2xx HTTP code -// - preflight response is missing CORS headers -// - preflight response is missing the PNA-specific `Access-Control` header -// - success -// -function makePreflightTests({ - key, - sourceName, - sourceServer, - sourceTreatAsPublic, - targetName, - targetServer, -}) { - const prefix = - `${sourceName} to ${targetName}: `; - - const source = { - server: sourceServer, - treatAsPublic: sourceTreatAsPublic, - }; - - promise_test_parallel(t => windowOpenExistingTest(t, { - source, - target: { - server: targetServer, - behavior: { preflight: PreflightBehavior.failure() }, - }, - expected: NavigationTestResult.FAILURE, - }), prefix + "failed preflight."); - - promise_test_parallel(t => windowOpenExistingTest(t, { - source, - target: { - server: targetServer, - behavior: { preflight: PreflightBehavior.noCorsHeader(token()) }, - }, - expected: NavigationTestResult.FAILURE, - }), prefix + "missing CORS headers."); - - promise_test_parallel(t => windowOpenExistingTest(t, { - source, - target: { - server: targetServer, - behavior: { preflight: PreflightBehavior.noPnaHeader(token()) }, - }, - expected: NavigationTestResult.FAILURE, - }), prefix + "missing PNA header."); - - promise_test_parallel(t => windowOpenExistingTest(t, { - source, - target: { - server: targetServer, - behavior: { preflight: PreflightBehavior.navigation(token()) }, - }, - expected: NavigationTestResult.SUCCESS, - }), prefix + "success."); -} - -// Source: private secure context. -// -// Navigating to the local address space require a successful preflight response -// carrying a PNA-specific header. - -subsetTestByKey('from-private', makePreflightTests, { - sourceServer: Server.HTTPS_PRIVATE, - sourceName: 'private', - targetServer: Server.HTTPS_LOCAL, - targetName: 'local', -}); - -subsetTestByKey( - 'from-private', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: {server: Server.HTTPS_PRIVATE}, - expected: NavigationTestResult.SUCCESS, - }), - 'private to private: no preflight required.'); - -subsetTestByKey( - 'from-private', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: {server: Server.HTTPS_PUBLIC}, - expected: NavigationTestResult.SUCCESS, - }), - 'private to public: no preflight required.'); - -// Source: public secure context. -// -// Navigating to the local and private address spaces require a successful -// preflight response carrying a PNA-specific header. - -subsetTestByKey('from-public', makePreflightTests, { - sourceServer: Server.HTTPS_PUBLIC, - sourceName: "public", - targetServer: Server.HTTPS_LOCAL, - targetName: "local", -}); - -subsetTestByKey('from-public', makePreflightTests, { - sourceServer: Server.HTTPS_PUBLIC, - sourceName: "public", - targetServer: Server.HTTPS_PRIVATE, - targetName: "private", -}); - -subsetTestByKey( - 'from-public', promise_test_parallel, - t => windowOpenExistingTest(t, { - source: {server: Server.HTTPS_PUBLIC}, - target: {server: Server.HTTPS_PUBLIC}, - expected: NavigationTestResult.SUCCESS, - }), - 'public to public: no preflight required.'); - -// The following tests verify that `CSP: treat-as-public-address` makes -// documents behave as if they had been served from a public IP address. - -subsetTestByKey('from-treat-as-public', makePreflightTests, { - sourceServer: Server.HTTPS_LOCAL, - sourceTreatAsPublic: true, - sourceName: "treat-as-public-address", - targetServer: Server.OTHER_HTTPS_LOCAL, - targetName: "local", -}); - -subsetTestByKey("from-treat-as-public", promise_test_parallel, - t => windowOpenExistingTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: {server: Server.HTTPS_LOCAL}, - expected: NavigationTestResult.SUCCESS, - }), - 'treat-as-public-address to local (same-origin): no preflight required.'); - -subsetTestByKey('from-treat-as-public', makePreflightTests, { - sourceServer: Server.HTTPS_LOCAL, - sourceTreatAsPublic: true, - sourceName: 'treat-as-public-address', - targetServer: Server.HTTPS_PRIVATE, - targetName: 'private', -}); - -subsetTestByKey("from-treat-as-public", promise_test_parallel, - t => windowOpenExistingTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: {server: Server.HTTPS_PUBLIC}, - expected: NavigationTestResult.SUCCESS, - }), - 'treat-as-public-address to public: no preflight required.'); diff --git a/tests/wpt/tests/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html b/tests/wpt/tests/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html new file mode 100644 index 00000000000..1c03382201e --- /dev/null +++ b/tests/wpt/tests/focus/focus-contenteditable-element-in-iframe-scroll-into-view.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset=utf-8> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>focus contenteditable element in iframe scroll into view</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<style> + +iframe { + position: absolute; + left: 250vw; +} + +.spacer { + width: 100vw; + height: 250vh; +} + +</style> +</head> +<body> + <div id="focusable-1" class="editor" contenteditable="true">focusable 1</div> + <div class="spacer"></div> + <iframe srcdoc="<div id='focusable-2' contenteditable='true'>focusable 2</div>"></iframe> + <div class="spacer"></div> +</body> +<script> + +function waitForLoad(w) { + return new Promise(resolve => w.addEventListener('load', resolve)); +} + +function waitForFrame() { + return new Promise(resolve => { + requestAnimationFrame(() => requestAnimationFrame(() => resolve())); + }); +} + +promise_test(async (t) => { + await waitForLoad(window); + const focusable_1 = document.getElementById("focusable-1"); + const iframeDocument = document.querySelector("iframe").contentDocument; + const focusable_2 = iframeDocument.getElementById("focusable-2"); + + focusable_1.focus(); + focusable_2.focus(); + await waitForFrame(); + const firstScrollX = window.scrollX; + const firstScrollY = window.scrollY; + + assert_greater_than(firstScrollX, window.innerWidth, "scroll X is greater than window.innerWidth"); + assert_greater_than(firstScrollY, window.innerHeight, "scroll Y is greater than window.innerHeight"); + + window.scroll(0, 0); + assert_equals(window.scrollX, 0, "scroll X is reset to 0"); + assert_equals(window.scrollY, 0, "scroll Y is reset to 0"); + + focusable_1.focus(); + focusable_2.focus(); + await waitForFrame(); + const secondScrollX = window.scrollX; + const secondScrollY = window.scrollY; + + // Ensure that both scroll positions are within +/- 1 + assert_approx_equals(firstScrollX, secondScrollX, 1.0, + "scroll X is within +/- 1 of a element in an iframe"); + assert_approx_equals(firstScrollY, secondScrollY, 1.0, + "scroll Y is within +/- 1 of a element in an iframe"); +}, "Check contenteditable element in an iframe scroll into view on second focusing"); + +</script> +</html> diff --git a/tests/wpt/tests/html/editing/dnd/events/ua-shadow-contents-manual.html b/tests/wpt/tests/html/editing/dnd/events/ua-shadow-contents-manual.html new file mode 100644 index 00000000000..23908ca9274 --- /dev/null +++ b/tests/wpt/tests/html/editing/dnd/events/ua-shadow-contents-manual.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html lang="en"> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body draggable="true" style="padding:20px"> +Drag this input down quickly. Try multiple times. No errors should be reported.<br> +<input type=color> + +<script> +document.body.addEventListener('dragenter', (e) => { + let target = e.relatedTarget; + while (target) { + assert_false(target instanceof ShadowRoot,'Drag events should not expose UA shadow roots'); + // This console log can also cause DevTools crashes, so this is explicitly + // left in on purpose: + console.log(target); + target = target.parentNode; + } +}); +</script> diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-ref.html b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-ref.html new file mode 100644 index 00000000000..03a21eb4573 --- /dev/null +++ b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-ref.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <style> + #foo { + height: 50px; + box-sizing: border-box; + } + #bar { + border-bottom-width: 0px; + box-sizing: border-box; + } + </style> +</head> +<body> + <hr id="foo"> + <hr id="bar"> +</body> +</html> + diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade-ref.html b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade-ref.html new file mode 100644 index 00000000000..d6300e250d9 --- /dev/null +++ b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade-ref.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <style> + hr { + border-width: 25px; + } + </style> +</head> +<body> + <hr color="black"> + <hr color="totally-not-a-color"> + <hr noshade> + <hr color="black" noshade> +</body> +</html> + diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade.html b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade.html new file mode 100644 index 00000000000..db1d583934e --- /dev/null +++ b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2" /> +<title>hr elements: Tests behaviour of a size attribute with color/noshade attributes present</title> +<link rel="author" title="Simon Wülker" href="mailto:simon.wuelker@arcor.de"> +<link rel="match" href="/html/rendering/non-replaced-elements/the-hr-element-0/size-with-color-or-noshade-ref.html"> +<meta name="assert" content="This checks that the size attribute of a hr element changes the border widths when color/noshade attributes are present"> +<body> + <hr size=50 color="black"> + <hr size=50 color="totally-not-a-color"> + <hr size=50 noshade> + <hr size=50 color="black" noshade> +</body> +</html> + diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size.html b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size.html new file mode 100644 index 00000000000..2162131b853 --- /dev/null +++ b/tests/wpt/tests/html/rendering/non-replaced-elements/the-hr-element-0/size.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2" /> +<title>hr elements: Tests behaviour of a size attribute without color/noshade attributes</title> +<link rel="author" title="Simon Wülker" href="mailto:simon.wuelker@arcor.de"> +<link rel="match" href="/html/rendering/non-replaced-elements/the-hr-element-0/size-ref.html"> +<meta name="assert" content="This checks that the size attribute of a hr element changes its height."> +<body> + <hr size=50> + <hr size=1> +</body> +</html> + diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-path-changes-svg.tentative.html b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-path-changes-svg.tentative.html index 1bc53a1f18e..3ef59c37a85 100644 --- a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-path-changes-svg.tentative.html +++ b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-path-changes-svg.tentative.html @@ -13,25 +13,25 @@ // ------------------- promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png?image-decode-path-changes-1"); var promise = img.decode(); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.svg"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.svg?image-decode-path-changes-1"); return promise_rejects_dom(t, "EncodingError", promise); }, document.title + " xlink:href changes fail decode."); promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttribute('href', "/images/green.png"); + img.setAttribute('href', "/images/green.png?image-decode-path-changes-2"); var promise = img.decode(); - img.setAttribute('href', "/images/green.svg"); + img.setAttribute('href', "/images/green.svg?image-decode-path-changes-2"); return promise_rejects_dom(t, "EncodingError", promise); }, document.title + " href changes fail decode."); promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png?image-decode-path-changes-3"); var first_promise = img.decode(); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.svg"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.svg?image-decode-path-changes-3"); var second_promise = img.decode(); assert_not_equals(first_promise, second_promise); return Promise.all([ @@ -42,9 +42,9 @@ promise_test(function(t) { promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttribute('href', "/images/green.png"); + img.setAttribute('href', "/images/green.png?image-decode-path-changes-4"); var first_promise = img.decode(); - img.setAttribute('href', "/images/green.svg"); + img.setAttribute('href', "/images/green.svg?image-decode-path-changes-4"); var second_promise = img.decode(); assert_not_equals(first_promise, second_promise); return Promise.all([ @@ -55,9 +55,9 @@ promise_test(function(t) { promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png?image-decode-path-changes-5"); var first_promise = img.decode(); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/non/existent/path.png"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/non/existent/path.png?image-decode-path-changes-5"); var second_promise = img.decode(); assert_not_equals(first_promise, second_promise); return Promise.all([ @@ -68,9 +68,9 @@ promise_test(function(t) { promise_test(function(t) { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttribute('href', "/images/green.png"); + img.setAttribute('href', "/images/green.png?image-decode-path-changes-6"); var first_promise = img.decode(); - img.setAttribute('href', "/non/existent/path.png"); + img.setAttribute('href', "/non/existent/path.png?image-decode-path-changes-6"); var second_promise = img.decode(); assert_not_equals(first_promise, second_promise); return Promise.all([ diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html index 0fc49e60360..fbc7143ecee 100644 --- a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html +++ b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html @@ -9,9 +9,11 @@ <script> "use strict"; +let png = "/images/green.png?image-decode-with-quick-attach-" + Math.random(); + promise_test(function() { var img = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png"); + img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', png); const promise = img.decode().then(function(arg) { assert_equals(arg, undefined); }); diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html index df9eb374b5a..ae6fa0e4328 100644 --- a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html +++ b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html @@ -1,4 +1,5 @@ <!doctype html> +<head> <meta charset="utf-8"> <title>HTMLImageElement naturalWidth/naturalHeight behavior for SVG that lacks at least one natural dimension</title> <!-- Note: this test asserts a different expectation from what the HTML spec @@ -6,7 +7,11 @@ behavior doesn't appear to be web-compatible for some of the cases here, and issue https://github.com/whatwg/html/issues/11287 is filed on addresing that. In the meantime, this test is named with ".tentative" to - indicate that it's not authoritative. --> + indicate that it's not authoritative. After the spec change is accepted, + we can remove the neighboring naturalWidth-naturalHeight.html test which + asserts the prior spec text's expectations, since this test covers the + same ground but with its expectations set according to the + soon-to-be-updated spec text. --> <link rel="help" href="https://github.com/whatwg/html/issues/11287"> <link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-naturalwidth-dev"> <link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-width"> @@ -15,7 +20,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <style> -.scroller { +#scroller { /* We wrap all the test content in a scroller so that it doesn't push * the textual test-results too far out of view. */ @@ -24,7 +29,7 @@ width: max-content; overflow: scroll; } -.container { +#containingBlock { /* There are a few SVG images here that size so that their margin-box fills * their containing block width. We define a specific size here so that we * can then check for it (minus the margins) in the "data-width" attribute. @@ -35,13 +40,24 @@ img { /* This styling is just cosmetic, to help visualize the images. */ border: 5px solid teal; margin: 5px; - vertical-align: top; display: block; - width: max-content; } </style> -<div class="scroller"> - <div class="container"> +<!-- We specify the img elements in a <template> and then clone them for + testing, so that we can dynamically generate and test several variants + of each img. --> +<template id="imgTemplates"> +<!-- For each img element: + * The "data-natural-{width,height}" attributes represent the expected + values of the img element's "naturalWidth" and "naturalHeight" IDL + attributes. This test implicitly expects the "width" and "height" IDL + attributes to have those same expected values; but in cases where that's + not correct, we provide the actual expected value in the + "data-{width,height}" attributes (as distinguished from + data-natural-{width,height}). + * The "title" attribute is a description of the scenario being tested, and + it must be unique to satisfy the test harness requirements. --> + <!-- FIRST PART OF TEST: No viewBox. Just a missing (or edge-casey, i.e. negative or percent-valued) values, for the width and height attrs on the root svg element in a SVG image. --> @@ -163,18 +179,37 @@ img { <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' height='-5' viewBox='0 0 600 200'></svg>" title="SVG image, with natural width and height being negative, and aspect ratio from viewBox" data-natural-width="0" data-natural-height="0"> +</template> +</head> +<body> +<div id="scroller"> + <div id="containingBlock"> + </div> </div> -</div> +<!-- We generate and append all of the tested <img> elements while we're inside + the <body>, so that all of the <img> elements' "load" events will block + the window onload event: --> <script> setup({explicit_done:true}); +// Clone and append a copy of the contents of imgTemplates, for testing: +let clone = imgTemplates.content.cloneNode("true"); +containingBlock.appendChild(clone); + +// After all the img elements have loaded (indicated by the window load event), +// we run the various tests: onload = function() { Array.from(document.images).forEach(img => { test(function() { + // We expect naturalWidth to match the provided data-natural-width + // (and similar for 'height'). const expectedNaturalWidth = parseFloat(img.dataset.naturalWidth); const expectedNaturalHeight = parseFloat(img.dataset.naturalHeight); assert_equals(img.naturalWidth, expectedNaturalWidth, 'naturalWidth'); assert_equals(img.naturalHeight, expectedNaturalHeight, 'naturalHeight'); + // If 'data-width' is provided, then we expect img.width to match it. + // Otherwise we expect img.width to match the 'data-natural-width'. + // (And similar for 'height'.) const expectedWidth = 'width' in img.dataset ? parseFloat(img.dataset.width) : expectedNaturalWidth; const expectedHeight = 'height' in img.dataset ? @@ -187,3 +222,4 @@ onload = function() { done(); }; </script> +</body> diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-highlight-crash.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-highlight-crash.html new file mode 100644 index 00000000000..a45120a2459 --- /dev/null +++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-highlight-crash.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://issues.chromium.org/issues/419167530"> + +<style> + @container (width) { + div::highlight(custom-highlight) { + --foo: bar; + } + } +</style> + +<select> + <div style="container-type:inline-size"></div> +</select> diff --git a/tests/wpt/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html b/tests/wpt/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html deleted file mode 100644 index 0b3d8dc9881..00000000000 --- a/tests/wpt/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html +++ /dev/null @@ -1,68 +0,0 @@ -<!DOCTYPE html> -<meta charset=utf-8> -<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<body> -<!--The permission element should not allow setting negative outline-offset or margins under 4px. ---> -<style> - #id1 { - outline-offset: -50px; - margin-top: 3px; - margin-left: -50px; - margin-bottom: 0px; - margin-right: -50px; - } - #id2 { - outline-offset: 50px; - margin-top: 50px; - margin-left: 50px; - margin-bottom: 50px; - margin-right: 50px; - } - - /* These various expressions all result in a negative value when calculated */ - #id3 { - outline-offset: min(-50px, 50px); - margin-top: min(10%, -50px); - margin-left: clamp(-100px, 1vw, -50px); - margin-bottom: 1% - 10000px; - margin-right: max(min(-1em, 10em), -5%); - } -</style> - - -<permission id="id1" type="geolocation"></permission> -<permission id="id2" type="camera"></permission> -<permission id="id3" type="microphone"></permission> - -<script> - test(function(){ - var el_with_negatives = document.getElementById("id1"); - assert_equals(getComputedStyle(el_with_negatives).outlineOffset, "0px", "outline-offset"); - assert_equals(getComputedStyle(el_with_negatives).marginLeft, "4px", "margin-left"); - assert_equals(getComputedStyle(el_with_negatives).marginRight, "4px", "margin-right"); - assert_equals(getComputedStyle(el_with_negatives).marginTop, "4px", "margin-top"); - assert_equals(getComputedStyle(el_with_negatives).marginBottom, "4px", "margin-bottom"); - }, "Negative margins/offset should be changed to 4px"); - - test(function(){ - var el_with_positives = document.getElementById("id2"); - assert_equals(getComputedStyle(el_with_positives).outlineOffset, "50px", "outline-offset"); - assert_equals(getComputedStyle(el_with_positives).marginLeft, "50px", "margin-left"); - assert_equals(getComputedStyle(el_with_positives).marginRight, "50px", "margin-right"); - assert_equals(getComputedStyle(el_with_positives).marginTop, "50px", "margin-top"); - assert_equals(getComputedStyle(el_with_positives).marginBottom, "50px", "margin-bottom"); - }, "Positive margins/offset are unaffected"); - - test(function(){ - var el_with_negative_expr = document.getElementById("id3"); - assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); - assert_equals(getComputedStyle(el_with_negative_expr).marginLeft, "4px", "margin-left"); - assert_equals(getComputedStyle(el_with_negative_expr).marginRight, "4px", "margin-right"); - assert_equals(getComputedStyle(el_with_negative_expr).marginTop, "4px", "margin-top"); - assert_equals(getComputedStyle(el_with_negative_expr).marginBottom, "4px", "margin-bottom"); - }, "Expressions margins/offset should always return at least 4px"); -</script> -</body>
\ No newline at end of file diff --git a/tests/wpt/tests/html/semantics/permission-element/negative-offset.tentative.html b/tests/wpt/tests/html/semantics/permission-element/negative-offset.tentative.html new file mode 100644 index 00000000000..c1424ad9cc8 --- /dev/null +++ b/tests/wpt/tests/html/semantics/permission-element/negative-offset.tentative.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<!--The permission element should not allow setting negative outline-offset. +--> +<style> + #id1 { + outline-offset: -50px; + } + #id2 { + outline-offset: 50px; + } + + /* These various expressions all result in a negative value when calculated */ + #id3 { + outline-offset: min(-50px, 50px); + } + #id4 { + outline-offset: min(10%, -50px); + } + #id5 { + outline-offset: clamp(-100px, 1vw, -50px); + } + #id6 { + outline-offset: 1% - 10000px; + } + #id7 { + outline-offset: max(min(-1em, 10em), -5%); + } +</style> + +<permission id="id1" type="geolocation"></permission> +<permission id="id2" type="camera"></permission> +<permission id="id3" type="microphone"></permission> +<permission id="id4" type="camera"></permission> +<permission id="id5" type="geolocation"></permission> +<permission id="id6" type="microphone"></permission> +<permission id="id7" type="camera microphone"></permission> + +<script> + test(function(){ + var el_with_negatives = document.getElementById("id1"); + assert_equals(getComputedStyle(el_with_negatives).outlineOffset, "0px", "outline-offset"); + }, "Negative offset should be changed to 0px"); + + test(function(){ + var el_with_positives = document.getElementById("id2"); + assert_equals(getComputedStyle(el_with_positives).outlineOffset, "50px", "outline-offset"); + }, "Positive offset are unaffected"); + + test(function(){ + var el_with_negative_expr = document.getElementById("id3"); + assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); + }, "Expressions offset min(-50px, 50px) should return at least 0px"); + + test(function(){ + var el_with_negative_expr = document.getElementById("id4"); + assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); + }, "Expressions offset outline-offset: min(10%, -50px) should return at least 0px"); + + test(function(){ + var el_with_negative_expr = document.getElementById("id5"); + assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); + }, "Expressions offset clamp(-100px, 1vw, -50px) should return at least 0px"); + + test(function(){ + var el_with_negative_expr = document.getElementById("id6"); + assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); + }, "Expressions offset 1% - 10000px should return at least 0px"); + + test(function(){ + var el_with_negative_expr = document.getElementById("id7"); + assert_equals(getComputedStyle(el_with_negative_expr).outlineOffset, "0px", "outline-offset"); + }, "Expressions offset max(min(-1em, 10em), -5%) should return at least 0px"); +</script> +</body>
\ No newline at end of file diff --git a/tests/wpt/tests/html/semantics/permission-element/no-focus.tentative.html b/tests/wpt/tests/html/semantics/permission-element/no-focus.tentative.html index 96467885183..1bf29634605 100644 --- a/tests/wpt/tests/html/semantics/permission-element/no-focus.tentative.html +++ b/tests/wpt/tests/html/semantics/permission-element/no-focus.tentative.html @@ -18,35 +18,34 @@ <script> promise_test(async() => { + invalid_permission_element.focus(); + assert_equals(document.activeElement, invalid_permission_element, + "Invalid permission element should be focusable"); + + focusable_span.focus(); valid_permission_element.focus(); - assert_equals(document.activeElement, document.body, - "Permission element should not be focused. Instead the parent element gets focus."); + assert_equals(document.activeElement, focusable_span, + "Permission element should not be focused."); + focusable_span.focus(); + await test_driver.bless('Focus with user activation', () => { + valid_permission_element.focus(); + }); + assert_equals(document.activeElement, valid_permission_element, + "Focus is allowed with user activation"); + + focusable_span.focus(); actions = new test_driver.Actions() .pointerMove(1, 1, {origin: valid_permission_element}) .pointerDown() .addTick(); await actions.send(); - assert_equals(document.activeElement, valid_permission_element, - "Users can still focus the element"); + "Users can focus the element"); focusable_span.focus(); assert_equals(document.activeElement, focusable_span, - "Other element should be focused"); - - invalid_permission_element.focus(); - assert_equals(document.activeElement, focusable_span, - "Invalid permission element should not be focused"); - - actions = new test_driver.Actions() - .pointerMove(1, 1, {origin: invalid_permission_element}) - .pointerDown() - .addTick(); - await actions.send(); - - assert_equals(document.activeElement, invalid_permission_element, - "Permission elements with an invalid-type can be focused like any other HTML element"); -}, "Permission element is not focusable by script"); + "Other element should be focused"); +}, "Permission element is not focusable by script without user activation"); </script> </body>
\ No newline at end of file diff --git a/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html b/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html new file mode 100644 index 00000000000..79055da1bad --- /dev/null +++ b/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-hidden-reftest.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>The icon of the location permission element should not be visibe if it is set to display:none</title> +<!-- TODO: Update the link to the permission icon spec --> +<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md"> +<link rel="mismatch" href="standard-location-permission-element-ref.html"> +<style> + ::permission-icon { + display: none; + } +</style> +<permission id="geolocation" type="geolocation"/> diff --git a/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html b/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html new file mode 100644 index 00000000000..d51b1c4d398 --- /dev/null +++ b/tests/wpt/tests/html/semantics/permission-element/permission-icon/icon-unique-per-type-reftest.html @@ -0,0 +1,6 @@ +<!doctype html> +<title>The camera permission element icon should be different to the location permission element</title> +<!-- TODO: Update the link to the permission icon spec --> +<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md"> +<link rel="mismatch" href="standard-location-permission-element-ref.html"> +<permission id="camera" type="camera"/> diff --git a/tests/wpt/tests/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html b/tests/wpt/tests/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html new file mode 100644 index 00000000000..15ffe751c51 --- /dev/null +++ b/tests/wpt/tests/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>A standard permission element of type location, without any non-default styling</title> +<permission id="geolocation" type="geolocation"/> diff --git a/tests/wpt/tests/html/semantics/popovers/popover-root-crash.html b/tests/wpt/tests/html/semantics/popovers/popover-root-crash.html new file mode 100644 index 00000000000..86498607730 --- /dev/null +++ b/tests/wpt/tests/html/semantics/popovers/popover-root-crash.html @@ -0,0 +1,7 @@ +<!doctype html> +<script> + window.addEventListener("load", async () => { + document.documentElement.popover = "manual" + document.documentElement.togglePopover(true) + }) +</script> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/042.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/042.html deleted file mode 100644 index df3a2f88f29..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/042.html +++ /dev/null @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: DOM mutation events when adding scripts: DOMNodeInserted </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - document.addEventListener( 'DOMNodeInserted', function(){ log('DOMNodeInserted'); }, false ); - testlib.addScript('log(\'head script #1\')', {}, document.getElementsByTagName('head')[0], false); - log('end script #1'); - </script> - - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - function test() { - assert_array_equals(eventOrder, ['inline script #1', 'head script #1', 'DOMNodeInserted', 'end script #1', 'inline script #2']); - t.done(); - } - onload = t.step_func(test) - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/043.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/043.html deleted file mode 100644 index bcfd90cba47..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/043.html +++ /dev/null @@ -1,31 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: DOM mutation events when adding external scripts: DOMNodeInserted </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - document.addEventListener( 'DOMNodeInserted', function(){ log('DOMNodeInserted'); }, false ); - testlib.addScript('', { src: 'scripts/include-1.js' }, document.getElementsByTagName('head')[0], false); - log('end script #1'); - </script> - - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - function test() { - assert_any(assert_array_equals, eventOrder, [['inline script #1', 'DOMNodeInserted', 'end script #1', 'external script #1', 'inline script #2'], - ['inline script #1', 'DOMNodeInserted', 'end script #1', 'inline script #2', 'external script #1']] - ); - t.done(); - } - onload = t.step_func(test) - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/044.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/044.html deleted file mode 100644 index 8d412079e45..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/044.html +++ /dev/null @@ -1,28 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: DOM mutation events when adding scripts: DOMNodeInsertedIntoDocument </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - testlib.addScript('log(\'head script #1\')', {}, document.getElementsByTagName('head')[0], false, function(s){s.addEventListener( 'DOMNodeInsertedIntoDocument', function(){ log('DOMNodeInsertedIntoDocument'); }, false ); } ); - log('end script #1'); - </script> - - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - function test() { - assert_array_equals(eventOrder, ['inline script #1', 'head script #1', 'DOMNodeInsertedIntoDocument', 'end script #1', 'inline script #2']); - t.done(); - } - onload = t.step_func(test) - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/045.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/045.html deleted file mode 100644 index 254e0d13662..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/045.html +++ /dev/null @@ -1,28 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: DOM mutation events when adding external scripts: DOMNodeInsertedIntoDocument </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - testlib.addScript('', {src:'scripts/include-1.js'}, document.getElementsByTagName('head')[0], false, function(s){s.addEventListener( 'DOMNodeInsertedIntoDocument', function(){ log('DOMNodeInsertedIntoDocument'); }, false);}); - log('end script #1'); - </script> - - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - onload = t.step_func(function() { - assert_any(assert_array_equals, eventOrder, [['inline script #1', 'DOMNodeInsertedIntoDocument', 'end script #1', 'external script #1', 'inline script #2'], - ['inline script #1', 'DOMNodeInsertedIntoDocument', 'end script #1', 'inline script #2', 'external script #1']]); - t.done(); - }); - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/054.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/054.html deleted file mode 100644 index 29ede23414e..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/054.html +++ /dev/null @@ -1,33 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: removing newly inserted script from DOMNodeInserted handler - external script </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - document.addEventListener( 'DOMNodeInserted', function listener(e){ - log('DOMNodeInserted event'); - e.target.parentNode.removeChild(e.target); - document.removeEventListener('DOMNodeInserted', listener); - }, false ); - var script=testlib.addScript('', { src:'scripts/include-1.js?'+Math.random() }, document.getElementsByTagName('body')[0], true ); - log('end script #1'); - </script> - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - function test() { - assert_any(assert_array_equals, eventOrder, [['inline script #1', 'DOMNodeInserted event', 'end script #1', 'inline script #2', 'external script #1'], - ['inline script #1', 'DOMNodeInserted event', 'end script #1', 'external script #1', 'inline script #2']]); - t.done(); - } - onload = t.step_func(test); - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/055.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/055.html deleted file mode 100644 index c837d78174b..00000000000 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/execution-timing/055.html +++ /dev/null @@ -1,32 +0,0 @@ -<!DOCTYPE html> -<html><head> - <title> scheduler: removing newly inserted script from DOMNodeInserted handler - inline script </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="testlib/testlib.js"></script> -</head> -<body> - - <div id="log">FAILED (This TC requires JavaScript enabled)</div> - - <script>log('inline script #1'); - document.addEventListener( 'DOMNodeInserted', function listener(e){ - log('DOMNodeInserted event'); - e.target.parentNode.removeChild(e.target); - document.removeEventListener('DOMNodeInserted', listener); - }, false ); - var script=testlib.addScript('log(\'added script\')', { }, document.getElementsByTagName('body')[0], true ); - log('end script #1'); - </script> - <script type="text/javascript"> - log( 'inline script #2' ); - var t = async_test() - - function test() { - assert_array_equals(eventOrder, ['inline script #1', 'added script', 'DOMNodeInserted event', 'end script #1', 'inline script #2']); - t.done(); - } - onload = t.step_func(test); - </script> - -</body></html> diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js index d15fa3f1b70..d0bb6aa9fb1 100644 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js +++ b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js @@ -7,6 +7,12 @@ const content_types = [ "text/json+blah", "application/blahjson", "image/json", + "text+json", + "json+json", + "text/json/json+json", + "text/html;+json", + "text/html+json+xml", + "text/json/json", ]; for (const content_type of content_types) { promise_test(async test => { diff --git a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html index 3232b84d271..fdeba93ba89 100644 --- a/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html +++ b/tests/wpt/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html @@ -19,6 +19,8 @@ const t3 = async_test("text/html+json"); const t4 = async_test("image/svg+json"); const t5 = async_test("text/json;boundary=something"); const t6 = async_test("text/json;foo=bar"); +const t7 = async_test("text/json;+json"); +const t8 = async_test("text/html+xml+json"); </script> <script type="module" onerror="t1.step(() => assert_unreached(event))"> import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json" with { type: "json"}; @@ -43,4 +45,12 @@ check(t5, v); <script type="module" onerror="t6.step(() => assert_unreached(event))"> import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json;foo=bar" with { type: "json"}; check(t6, v); +</script> +<script type="module" onerror="t7.step(() => assert_unreached(event))"> +import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json;%2Bjson" with { type: "json"}; +check(t7, v); +</script> +<script type="module" onerror="t8.step(() => assert_unreached(event))"> +import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/html%2Bxml%2Bjson" with { type: "json"}; +check(t8, v); </script>
\ No newline at end of file diff --git a/tests/wpt/tests/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html b/tests/wpt/tests/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html new file mode 100644 index 00000000000..885b75a3387 --- /dev/null +++ b/tests/wpt/tests/html/semantics/the-button-element/command-and-commandfor/source-attribute-retargeting.tentative.html @@ -0,0 +1,132 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id=popover popover=auto>popover</div> +<div id=host> + <template shadowrootmode=open> + <button id=shadow-button command=show-popover>button in shadowroot</button> + </template> +</div> + +<script> +promise_test(async () => { + const popover = document.getElementById('popover'); + const host = document.getElementById('host'); + const shadowButton = host.shadowRoot.getElementById('shadow-button'); + shadowButton.commandForElement = popover; + + const eventNames = ['beforetoggle', 'toggle', 'command']; + const eventNameToEvent = {}; + const eventNameToCaptureSource = {}; + const eventNameToBubbleSource = {}; + + for (const eventName of eventNames) { + popover.addEventListener(eventName, event => { + eventNameToEvent[eventName] = event; + eventNameToBubbleSource[eventName] = event.source; + }); + popover.addEventListener(eventName, event => { + eventNameToCaptureSource[eventName] = event.source; + }, {capture: true}); + } + + shadowButton.click(); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + + for (const eventName of eventNames) { + const event = eventNameToEvent[eventName]; + assert_true(!!event, `A ${eventName} event should have been fired.`); + assert_equals(eventNameToCaptureSource[eventName], host, + `${eventName}.source during capture.`); + assert_equals(eventNameToBubbleSource[eventName], host, + `${eventName}.source during bubble.`); + assert_not_equals(event.source, shadowButton, + `${eventName}.source shouldn't leak the shadow button.`); + assert_equals(event.source, host, + `${eventName}.source after dispatch.`); + } +}, 'CommandEvent.source and ToggleEvent.source should be retargeted during and after event dispatch.'); +</script> + +<div id=host2> + <template shadowrootmode=open> + <div id=source>source</div> + <div id=innerhost> + <template shadowrootmode=open> + <div id=target>target</div> + </template> + </div> + </template> +</div> + +<script> +// This does not test ToggleEvent because ToggleEventInit does not have a source attribute. +promise_test(async () => { + const host2 = document.getElementById('host2'); + const source = host2.shadowRoot.getElementById('source'); + const innerhost = host2.shadowRoot.getElementById('innerhost'); + const target = innerhost.shadowRoot.getElementById('target'); + + const targets = [host2, innerhost, target]; + const targetToEvent = new Map(); + const targetToCaptureSource = new Map(); + const targetToBubbleSource = new Map(); + + for (const target of targets) { + target.addEventListener('command', event => { + targetToEvent.set(target, event); + targetToBubbleSource.set(target, event.source); + }); + target.addEventListener('command', event => { + targetToCaptureSource.set(target, event.source); + }, {capture: true}); + } + + const commandEvent = new CommandEvent('command', {composed: true, source}); + target.dispatchEvent(commandEvent); + + for (const target of targets) { + const expectedSource = target == host2 ? host2 : source; + assert_true(targetToEvent.has(target), + `${target.id}: event should have fired.`); + assert_equals(targetToCaptureSource.get(target), expectedSource, + `${target.id}: event.source at capture.`); + assert_equals(targetToBubbleSource.get(target), expectedSource, + `${target.id}: event.source at bubble.`); + assert_equals(targetToEvent.get(target).source, host2, + `${target.id}: event.source after dispatch.`); + } +}, 'CommandEvent.source should be retargeted when manually dispatched with composed set to true.'); +</script> + +<div id=popover3 popover=auto>popover 3</div> +<button id=button3 commandfor=popover3 command=show-popover>show popover 3</button> + +<script> +promise_test(async () => { + const button = document.getElementById('button3'); + const popover = document.getElementById('popover3'); + + const eventNames = ['beforetoggle', 'toggle', 'command']; + const eventNameToEvent = {}; + for (const eventName of eventNames) { + popover.addEventListener(eventName, event => { + eventNameToEvent[eventName] = event; + }); + } + + button.click(); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + + for (const eventName of eventNames) { + const event = eventNameToEvent[eventName]; + assert_true(!!event, `${eventName} should have been fired.`); + assert_equals(event.source, button, + `${eventName}.source should be the invoker button after dispatch.`); + } +}, 'CommandEvent.source and ToggleEvent.source should not be set to null after dispatch without ShadowDOM.'); +</script> diff --git a/tests/wpt/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/WEB_FEATURES.yml b/tests/wpt/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/WEB_FEATURES.yml index a1af3e21a48..7a364e14095 100644 --- a/tests/wpt/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/WEB_FEATURES.yml +++ b/tests/wpt/tests/html/webappapis/system-state-and-capabilities/the-navigator-object/WEB_FEATURES.yml @@ -2,3 +2,7 @@ features: - name: pdf-viewer files: - plugins-and-mimetypes.html +- name: ua-client-hints + files: + - navigator_user_agent.tentative.html + - navigator_user_agent.https.tentative.html diff --git a/tests/wpt/tests/interfaces/scoped-custom-elements-registry.idl b/tests/wpt/tests/interfaces/scoped-custom-elements-registry.idl new file mode 100644 index 00000000000..46ca2d6b9c4 --- /dev/null +++ b/tests/wpt/tests/interfaces/scoped-custom-elements-registry.idl @@ -0,0 +1,38 @@ +[Exposed=Window] +partial interface CustomElementRegistry { + constructor(); + undefined initialize(Node root); +}; + +[Exposed=Window] +partial interface HTMLTemplateElement { + [CEReactions] attribute DOMString shadowRootCustomElementRegistry; +}; + +[Exposed=Window] +partial interface Document { + readonly attribute CustomElementRegistry? customElementRegistry; +}; + +[Exposed=Window] +partial interface Element { + readonly attribute CustomElementRegistry? customElementRegistry; +}; + +[Exposed=Window] +partial interface ShadowRoot { + readonly attribute CustomElementRegistry? customElementRegistry; +}; + +dictionary ImportNodeOptions { + CustomElementRegistry customElementRegistry; + boolean selfOnly = false; +}; + +partial dictionary ShadowRootInit { + CustomElementRegistry customElementRegistry; +}; + +partial dictionary ElementCreationOptions { + CustomElementRegistry customElementRegistry; +}; diff --git a/tests/wpt/tests/layout-instability/WEB_FEATURES.yml b/tests/wpt/tests/layout-instability/WEB_FEATURES.yml new file mode 100644 index 00000000000..335b072c186 --- /dev/null +++ b/tests/wpt/tests/layout-instability/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: layout-instability + files: "**" diff --git a/tests/wpt/tests/lint.ignore b/tests/wpt/tests/lint.ignore index 10b5dadba74..60b0f65a6f4 100644 --- a/tests/wpt/tests/lint.ignore +++ b/tests/wpt/tests/lint.ignore @@ -126,6 +126,7 @@ CONSOLE: webaudio/resources/audit.js:41 # Intentional use of console.* CONSOLE: infrastructure/webdriver/bidi/subscription.html CONSOLE: infrastructure/webdriver/bidi/subscription.window.js +CONSOLE: html/editing/dnd/events/ua-shadow-contents-manual.html # use of console in a public library - annotation-model ensures # it is not actually used diff --git a/tests/wpt/tests/network-error-logging/support/nel.sub.js b/tests/wpt/tests/network-error-logging/support/nel.sub.js index 26ddd897c2f..f9dfec1dad8 100644 --- a/tests/wpt/tests/network-error-logging/support/nel.sub.js +++ b/tests/wpt/tests/network-error-logging/support/nel.sub.js @@ -18,6 +18,7 @@ function releaseNELLock() { function nel_test(callback, name, properties) { promise_test(async t => { await obtainNELLock(); + await assertNELIsImplemented(); await clearReportingAndNELConfigurations(); await callback(t); await releaseNELLock(); @@ -27,6 +28,7 @@ function nel_test(callback, name, properties) { function nel_iframe_test(callback, name, properties) { promise_test(async t => { await obtainNELLock(); + await assertNELIsImplemented(); await clearReportingAndNELConfigurationsInIframe(); await callback(t); await releaseNELLock(); @@ -251,9 +253,10 @@ function _isSubsetOf(obj1, obj2) { * expected. */ -async function reportExists(expected, retain_reports) { - var timeout = - document.querySelector("meta[name=timeout][content=long]") ? 50 : 1; +async function reportExists(expected, retain_reports, timeout) { + if (!timeout) { + timeout = document.querySelector("meta[name=timeout][content=long]") ? 50 : 1; + } var reportLocation = "/reporting/resources/report.py?op=retrieve_report&timeout=" + timeout + "&reportID=" + reportID; @@ -295,3 +298,13 @@ async function reportsExist(expected_reports, retain_reports) { } return true; } + +// this runs first to avoid testing on browsers not implementing NEL +async function assertNELIsImplemented() { + await fetchResourceWithBasicPolicy(); + // Assert that the report was generated + assert_implements(await reportExists({ + url: getURLForResourceWithBasicPolicy(), + type: "network-error" + }, false, 1), "'Basic NEL support: missing network-error report'"); +} diff --git a/tests/wpt/tests/pointerevents/persistentDeviceId/get-persistendeviceid-from-pointer-mouse-event.tentative.html b/tests/wpt/tests/pointerevents/persistentDeviceId/get-persistendeviceid-from-pointer-mouse-event.tentative.html new file mode 100644 index 00000000000..66fb63d54d1 --- /dev/null +++ b/tests/wpt/tests/pointerevents/persistentDeviceId/get-persistendeviceid-from-pointer-mouse-event.tentative.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<style> + div { + user-select: none; // Prevents text selection on drag. + } +</style> +<div id="logger" draggable="false"></div> +<div id="console"></div> +<!-- This test documents the current behavior in Chrome for some + pointerType == "mouse" events --> +<script> + function CheckDeviceIdOne(event) { + assert_equals(event.persistentDeviceId, 1, event.type + " deviceId is 1"); + } + + function CheckDeviceIdZero(event) { + assert_equals(event.persistentDeviceId, 0, event.type + " deviceId is 0"); + } + + window.addEventListener("pointerdown", CheckDeviceIdOne, false); + window.addEventListener("pointermove", CheckDeviceIdOne, false); + window.addEventListener("pointerover", CheckDeviceIdOne, false); + window.addEventListener("pointerup", CheckDeviceIdOne, false); + window.addEventListener("click", CheckDeviceIdZero, false); + + promise_test(async () => { + let actions = new test_driver.Actions() + .addPointer("TestPointer", "mouse") + .pointerDown() + .pointerMove(100, 100) + .pointerUp(); + + await actions.send(); + + }, 'PointerEvent.persistentDeviceId'); +</script> diff --git a/tests/wpt/tests/resize-observer/zoom.html b/tests/wpt/tests/resize-observer/zoom.html new file mode 100644 index 00000000000..77b4bc49fa7 --- /dev/null +++ b/tests/wpt/tests/resize-observer/zoom.html @@ -0,0 +1,55 @@ +<!doctype html> +<link rel="help" href="https://drafts.csswg.org/css-viewport/#zoom-om"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9398"> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<title>ResizeObserver sizes account for zoom</title> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + div { + width: 100px; + height: 100px; + border: 5px solid; + padding: 5px; + margin: 5px; + box-sizing: border-box; + } +</style> +<div></div> +<div style="zoom: 2"></div> +<div style="zoom: 4"></div> +<script> +promise_test(async function() { + let { promise, resolve } = Promise.withResolvers(); + let observer = new ResizeObserver(entries => { + resolve(entries); + }); + for (let div of document.querySelectorAll("div")) { + observer.observe(div); + } + let entries = await promise; + observer.disconnect(); + assert_equals(entries.length, 3, "Should have three entries"); + for (let entry of entries) { + assert_equals(entry.contentRect.top, 5, "content-rect top should be scaled by zoom"); + assert_equals(entry.contentRect.left, 5, "content-rect left should be scaled by zoom"); + assert_equals(entry.contentRect.width, 80, "content-rect width should be scaled by zoom"); + assert_equals(entry.contentRect.height, 80, "content-rect height should be scaled by zoom"); + + for (let sizeArray of [entry.borderBoxSize, entry.contentBoxSize, entry.devicePixelContentBoxSize]) { + assert_equals(sizeArray.length, 1, "Should have one box"); + } + let borderBoxSize = entry.borderBoxSize[0]; + let contentBoxSize = entry.contentBoxSize[0]; + let devicePixelContentBoxSize = entry.devicePixelContentBoxSize[0]; + assert_equals(borderBoxSize.inlineSize, 100, "border inline size should be scaled by zoom"); + assert_equals(borderBoxSize.blockSize, 100, "border block size should be scaled by zoom"); + assert_equals(contentBoxSize.inlineSize, 80, "content inline size should be scaled by zoom"); + assert_equals(contentBoxSize.blockSize, 80, "content block size should be scaled by zoom"); + assert_equals(devicePixelContentBoxSize.inlineSize, 80 * entry.target.currentCSSZoom * window.devicePixelRatio, "dev-px size should _not_ be scaled by zoom"); + assert_equals(devicePixelContentBoxSize.blockSize, 80 * entry.target.currentCSSZoom * window.devicePixelRatio, "dev-px size should _not_ be scaled by zoom"); + } +}); +</script> diff --git a/tests/wpt/tests/resource-timing/content-encoding.https.html b/tests/wpt/tests/resource-timing/content-encoding.https.html index 0d67bfc7d4f..80473552f08 100644 --- a/tests/wpt/tests/resource-timing/content-encoding.https.html +++ b/tests/wpt/tests/resource-timing/content-encoding.https.html @@ -33,10 +33,10 @@ run_same_origin_test("/resource-timing/resources/foo.text.zst", "zstd"); run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=deflate", "deflate"); run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=gzip", "gzip"); - // Unrecognized content encoding value should be transformed to "unknown". - run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=unrecognizedname", "unknown"); - // "identity" is not allowed in response header and should be transformed to "unknown". - run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=identity", "unknown"); + // Unrecognized content encoding value should be transformed to "@unknown". + run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=unrecognizedname", "@unknown"); + // "identity" is not allowed in response header and should be transformed to "@unknown". + run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=identity", "@unknown"); // Mult-encodinging and formatting tests. run_same_origin_test("/resource-timing/resources/content-encoding-headers.py?content_encoding=gzip, deflate,Apple", "multiple"); run_same_origin_test("/resource-timing/resources/content-encoding-headers.py?content_encoding=gzip, ", "multiple"); diff --git a/tests/wpt/tests/resources/testdriver-actions.js.headers b/tests/wpt/tests/resources/testdriver-actions.js.headers new file mode 100644 index 00000000000..5e8f640c665 --- /dev/null +++ b/tests/wpt/tests/resources/testdriver-actions.js.headers @@ -0,0 +1,2 @@ +Content-Type: text/javascript; charset=utf-8 +Cache-Control: max-age=3600 diff --git a/tests/wpt/tests/scroll-animations/animation-trigger/animation-trigger-repeat.tentative.html b/tests/wpt/tests/scroll-animations/animation-trigger/animation-trigger-repeat.tentative.html index cfbe9d3c933..6c01e762e5a 100644 --- a/tests/wpt/tests/scroll-animations/animation-trigger/animation-trigger-repeat.tentative.html +++ b/tests/wpt/tests/scroll-animations/animation-trigger/animation-trigger-repeat.tentative.html @@ -21,7 +21,7 @@ } .target { animation: myAnim linear 0.5s both; - animation-trigger: repeat; + animation-trigger-type: repeat; animation-trigger-range: 250px 300px; animation-trigger-exit-range: 200px 350px; } @@ -76,6 +76,7 @@ // let target; async function testRepeatAnimationTrigger(test, rangeBoundaries) { + const initial_transform = getComputedStyle(target).transform; // Just short of the trigger range start, no trigger action expected. await testAnimationTrigger(test, () => { return rangeBoundaries.exitTriggerRangeAbove(); @@ -91,15 +92,14 @@ return rangeBoundaries.enterTriggerRange(); }, target, ["animationstart", "animationend"], [true, true]); - // This is a repeat trigger, exiting the exit range resets the animation. - // We waited for an animationend event in the previous step so we won't - // see an animationcancel event here. But, by inspecting - // style.transform, we should see that the animation was reset. + // This is a repeat trigger, exiting the exit range resets the + // animation. By inspecting style.transform, we should see that the + // animation was reset. await testAnimationTrigger(test, () => { return rangeBoundaries.exitExitRangeAbove(); }, target, ["animationstart", "animationend", "animationcancel"], [false, false, false]); - assert_equals(getComputedStyle(target).transform, "none"); + assert_equals(getComputedStyle(target).transform, initial_transform); // This is a repeat trigger, re-entering plays the animation. await testAnimationTrigger(test, async () => { @@ -109,7 +109,7 @@ // Exit the range. return rangeBoundaries.exitExitRangeBelow(); }, target, ["animationstart", "animationend", "animationcancel"], - [true, false, true]); + [true, false, false]); } const CSS_TRIGGER_START_PX = 250; @@ -127,7 +127,7 @@ CSS_EXIT_END_PX, scroller); await testRepeatAnimationTrigger(test, rangeBoundaries); - }, "once animation triggered via scroll() timeline."); + }, "repeat animation triggered via scroll() timeline."); promise_test(async (test) => { scroller = view_scroller; @@ -142,7 +142,7 @@ COVER_START_OFFSET + CSS_EXIT_END_PX, scroller); await testRepeatAnimationTrigger(test, rangeBoundaries); - }, "once animation triggered via view() timeline."); + }, "repeat animation triggered via view() timeline."); promise_test(async (test) => { scroller = deferred_scroller; @@ -157,7 +157,7 @@ COVER_START_OFFSET + CSS_EXIT_END_PX, scroller); await testRepeatAnimationTrigger(test, rangeBoundaries); - }, "once animation triggered via deferred (view) timeline."); + }, "repeat animation triggered via deferred (view) timeline."); </script> </body> </html> diff --git a/tests/wpt/tests/shadow-dom/HighlightRegistry-highlightsFromPoint.html b/tests/wpt/tests/shadow-dom/HighlightRegistry-highlightsFromPoint.html index 5244f923e34..4098bc5a994 100644 --- a/tests/wpt/tests/shadow-dom/HighlightRegistry-highlightsFromPoint.html +++ b/tests/wpt/tests/shadow-dom/HighlightRegistry-highlightsFromPoint.html @@ -1,7 +1,7 @@ <!doctype html> <body> <meta name="author" title="Fernando Fiori" href="mailto:ffiori@microsoft.com"> -<meta name="assert" content="HighlightRegistry.highlightsFromPoint returns the Highlights present at at a given point inside the shadow roots passed as argument."> +<meta name="assert" content="HighlightRegistry.highlightsFromPoint returns HighlightHitResults with the Highlights and their corresponding ranges present at a given point inside the shadow roots passed as argument."> <link rel="help" href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/highlight/HighlightsFromPointsExplainer.md"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -57,25 +57,28 @@ body { // Get x and y coordinates between '0' and '1'. let x = spanBoundingRectangle.left + characterWidth; let y = spanBoundingRectangle.top + spanBoundingRectangle.height / 2; - let highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided point at no Highlights'); + let highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided point at no Highlights'); // Get x and y coordinates between '2' and '3'. x = spanBoundingRectangle.left + 3 * characterWidth; - highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one Highlight when the given coordinates point at a Highlight under the shadow root provided'); - assert_equals(highlights[0], highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates when it\'s under the shadow root provided'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns exactly one Highlight when the given coordinates point at a Highlight under the shadow root provided'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates when it\'s under the shadow root provided'); + assert_array_equals(highlight_hit_results[0].ranges, [range], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided point at one Highlight in the shadow DOM but shadowRoots provided is empty'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the coordinates provided point at one Highlight in the shadow DOM but shadowRoots provided is empty'); // Get x and y coordinates between '6' and '7'. // Same priority for the Highlights, break tie by order of registration. x = spanBoundingRectangle.left + 7 * characterWidth; - highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two Highlights when the coordinates provided point at two overlapping Highlights'); - assert_equals(highlights[0], highlight2, 'CSS.highlights.highlightsFromPoint() returns first the Highlight registered last when both Highlights present at the point provided have the same priority'); - assert_equals(highlights[1], highlight, 'CSS.highlights.highlightsFromPoint() returns last the Highlight registered first when both Highlights present at the point provided have the same priority'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 2, 'CSS.highlights.highlightsFromPoint() returns exactly two Highlights when the coordinates provided point at two overlapping Highlights'); + assert_equals(highlight_hit_results[0].highlight, highlight2, 'CSS.highlights.highlightsFromPoint() returns first the Highlight registered last when both Highlights present at the point provided have the same priority'); + assert_equals(highlight_hit_results[1].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns last the Highlight registered first when both Highlights present at the point provided have the same priority'); + assert_array_equals(highlight_hit_results[0].ranges, [range2], 'CSS.highlights.highlightsFromPoint() returns first a HighlightHitResult with the ranges of the Highlight present on top at the coordinates provided'); + assert_array_equals(highlight_hit_results[1].ranges, [range], 'CSS.highlights.highlightsFromPoint() returns last a HighlightHitResult with the ranges of the Highlight present at the bottom at the coordinates provided'); }, 'CSS.highlights.highlightsFromPoint() returns Highlights present at a given point inside a shadow tree in the right order.'); test(() => { @@ -109,23 +112,25 @@ body { // Get x and y coordinates between '0' and '1' in the first line. let x = spanBoundingRectangle.left + characterWidth; let y = container.getBoundingClientRect().top + characterHeight / 2.0; - let highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 1, 'CSS.highlights.highlightsFromPoint() returns one Highlight present at the coordinates provided'); - assert_equals(highlights[0], highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates even when no shadowRoots are provided because it\'s outside the shadow DOM'); + let highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns one Highlight present at the coordinates provided'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates even when no shadowRoots are provided because it\'s outside the shadow DOM'); + assert_array_equals(highlight_hit_results[0].ranges, [range], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); // Now move y to the second line (inside shadow DOM). y += characterHeight; - highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text under the shadow root provided even when there is a Highlight set with a Range that starts and ends in the regular DOM surrounding it, even when shadowRoots are provided'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text under the shadow root provided even when there is a Highlight set with a Range that starts and ends in the regular DOM surrounding it, even when shadowRoots are provided'); - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text under the shadow root provided even when there is a Highlight set with a Range that starts and ends in the regular DOM surrounding it'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text under the shadow root provided even when there is a Highlight set with a Range that starts and ends in the regular DOM surrounding it'); // Now move y to the third line. y += characterHeight; - highlights = CSS.highlights.highlightsFromPoint(x, y); - assert_equals(highlights.length, 1, 'CSS.highlights.highlightsFromPoint() returns one Highlight present at the coordinates provided'); - assert_equals(highlights[0], highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates because it\'s outside of the shadow DOM'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y); + assert_equals(highlight_hit_results.length, 1, 'CSS.highlights.highlightsFromPoint() returns one Highlight present at the coordinates provided'); + assert_equals(highlight_hit_results[0].highlight, highlight, 'CSS.highlights.highlightsFromPoint() returns the Highlight present at the given coordinates because it\'s outside of the shadow DOM'); + assert_array_equals(highlight_hit_results[0].ranges, [range], 'CSS.highlights.highlightsFromPoint() returns a HighlightHitResult with the ranges of the Highlight present at the coordinates provided'); // Set a Highlight with a range like this one: // [0123456789 @@ -138,13 +143,13 @@ body { // Set x and y coordinates between '0' and '1' in the first line. y = container.getBoundingClientRect().top + characterHeight / 2.0; - highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text in the light DOM that is not highlighted even when there is a Highlight set with a StaticRange that starts in the light DOM and ends in the shadow DOM surrounding it'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text in the light DOM that is not highlighted even when there is a Highlight set with a StaticRange that starts in the light DOM and ends in the shadow DOM surrounding it'); // Now move y to the second line (inside shadow DOM). y += characterHeight; - highlights = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); - assert_equals(highlights.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text in the shadow DOM that is not highlighted even when there is a Highlight set with a StaticRange that starts in the light DOM and ends in the shadow DOM surrounding it'); + highlight_hit_results = CSS.highlights.highlightsFromPoint(x, y, {shadowRoots: [shadowRoot]}); + assert_equals(highlight_hit_results.length, 0, 'CSS.highlights.highlightsFromPoint() returns no Highlights when the given coordinates point at text in the shadow DOM that is not highlighted even when there is a Highlight set with a StaticRange that starts in the light DOM and ends in the shadow DOM surrounding it'); }, 'CSS.highlights.highlightsFromPoint() doesn\'t return Highlights that are not painted at the given coordinates even when they fall inside the Highlights\' ranges'); </script> </body> diff --git a/tests/wpt/tests/soft-navigation-heuristics/first-interaction-not-softnav.tentative.html b/tests/wpt/tests/soft-navigation-heuristics/first-interaction-not-softnav.tentative.html index e0262021836..2c9e2aa7c01 100644 --- a/tests/wpt/tests/soft-navigation-heuristics/first-interaction-not-softnav.tentative.html +++ b/tests/wpt/tests/soft-navigation-heuristics/first-interaction-not-softnav.tentative.html @@ -1,36 +1,37 @@ -<!DOCTYPE HTML> +<!doctype html> <html> -<head> -<meta charset="utf-8"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-vendor.js"></script> -<script src="resources/soft-navigation-helper.js"></script> -</head> -<body> - <main id=main> - <p><a id=firstlink>Click me!</a></p> - <p><a id=secondlink>Then click me!</a></p> - </main> - <script> - (async () => { - if (test_driver) { - const firstlink = document.getElementById("firstlink"); - const clickPromise = new Promise(r => { - firstlink.addEventListener("click", r); - }); - test_driver.click(firstlink); - await clickPromise; - } - })(); - const secondlink = document.getElementById("secondlink"); - testSoftNavigation({ - addContent: () => { - addImageToMain(); - }, - link: secondlink, - test: "first interaction in the middle of a soft navigation"}); - </script> -</body> + <head> + <meta charset="utf-8" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/soft-navigation-helper.js"></script> + </head> + <body> + <main id="main"> + <p><a id="firstlink">Click me!</a></p> + <p><a id="secondlink">Then click me!</a></p> + </main> + <script> + const secondlink = document.getElementById("secondlink"); + testSoftNavigation({ + preTestWork: async () => { + if (test_driver) { + const firstlink = document.getElementById("firstlink"); + const clickPromise = new Promise((r) => { + firstlink.addEventListener("click", r); + }); + test_driver.click(firstlink); + await clickPromise; + } + }, + addContent: () => { + addImageToMain(); + }, + link: secondlink, + test: "first interaction before a soft navigation", + }); + </script> + </body> </html> diff --git a/tests/wpt/tests/soft-navigation-heuristics/innertext.tentative.html b/tests/wpt/tests/soft-navigation-heuristics/innertext.tentative.html deleted file mode 100644 index 7716488f25a..00000000000 --- a/tests/wpt/tests/soft-navigation-heuristics/innertext.tentative.html +++ /dev/null @@ -1,37 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> -<meta charset="utf-8"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-vendor.js"></script> -<script src="resources/soft-navigation-helper.js"></script> -</head> -<body> - <main id=main> - <a id=link>Click me!</a> - <!-- This test fails if the paragraph below already has content. The reason - is that secondary paints are not being properly recorded, and hence don't - count for soft navigation heuristics. --> - <p id="softnav-content"></p> - </main> - <script> - const link = document.getElementById("link"); - testSoftNavigation({ - addContent: async () => { - document.getElementById("softnav-content").innerText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' + - 'sed do eiusmod tempor incididunt ut labore et dolore magna ' + - 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation ' + - 'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis ' + - 'aute irure dolor in reprehenderit in voluptate velit esse ' + - 'cillum dolore eu fugiat nulla pariatur. Excepteur sint ' + - 'occaecat cupidatat non proident, sunt in culpa qui officia ' + - 'deserunt mollit anim id est laborum.'; - }, - link: link, - test: "Soft navigation when only innerText was modified"}); - </script> -</body> -</html> diff --git a/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js b/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js index 48e7b58d8d1..5860738225b 100644 --- a/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js +++ b/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js @@ -48,7 +48,11 @@ const testSoftNavigation = options => { const eventType = readValue(options.eventType, 'click'); const interactionFunc = options.interactionFunc; const eventPrepWork = options.eventPrepWork; + const preTestWork = options.preTestWork; promise_test(async t => { + if (preTestWork) { + await preTestWork(); + } await withTimeoutMessage( t, waitInitialLCP(), 'Timed out waiting for initial LCP'); const preClickLcp = await withTimeoutMessage( diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html index 66d23b22788..2e3c3809df6 100644 --- a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html +++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html @@ -61,6 +61,20 @@ document.body.appendChild(cloned); history.pushState({}, "", "/template-element"); } + + // Uses Element.innerText to add to the DOM, without overriding existing text. + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText + function elementInnerTextInitial() { + document.getElementById("element-inner-text-initial-dest").innerText = "Hello, World."; + history.pushState({}, "", "/element-inner-text-initial"); + } + + // Uses Element.innerText to add to the DOM, overriding existing text. + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText + function elementInnerTextOverride() { + document.getElementById("element-inner-text-override-dest").innerText = "Hello, World."; + history.pushState({}, "", "/element-inner-text-override"); + } </script> </head> <body> @@ -70,6 +84,14 @@ <div id="document-import-node" onclick="documentImportNode()">Click here!</div> <div id="document-adopt-node" onclick="documentAdoptNode()">Click here!</div> <div id="template-element" onclick="templateElement()">Click here!</div> + <div id="element-inner-text-initial" onclick="elementInnerTextInitial()"> + Click here! + <div id="element-inner-text-initial-dest"></div> + </div> + <div id="element-inner-text-override" onclick="elementInnerTextOverride()"> + Click here! + <div id="element-inner-text-override-dest">Some text already there.</div> + </div> <iframe id="iframe-example" srcdoc="<div id='import-this'>Hello, World.</div>"></iframe> @@ -111,6 +133,14 @@ "Soft Navigation Detection supports Document.adoptNode.", ); test_template("template-element", "Soft Navigation Detection supports template elements."); + test_template( + "element-inner-text-initial", + "Soft Navigation Detection supports Element.innerText when it does not override existing text.", + ); + test_template( + "element-inner-text-override", + "Soft Navigation Detection supports Element.innerText when it overrides existing text.", + ); </script> </body> </html> diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/resources/other_window.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/resources/other_window.html new file mode 100644 index 00000000000..406d39c3691 --- /dev/null +++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/resources/other_window.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<h1>This is some text</h1> + +<script> + function navigate() { + history.pushState({}, "", "/different-url"); + } + + async function getNextSoftNavEntry() { + return new Promise(resolve => { + new PerformanceObserver((list, observer) => { + observer.disconnect(); + resolve(list.getEntries()[0]); + }).observe({ type: "soft-navigation" }); + }); + } +</script> diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/window-open-cross-scheduling.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/window-open-cross-scheduling.html new file mode 100644 index 00000000000..1a41be6ddd2 --- /dev/null +++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/window-open-cross-scheduling.html @@ -0,0 +1,45 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <title>Scheduling soft navigations across windows.</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script></script> + </head> + <body> + <button id="button" onclick="navigateChild()">Press Me!</button> + + <script> + const child = window.open('resources/other_window.html'); + const childLoaded = new Promise(resolve => child.onload = resolve); + + function navigateChild() { + // `child.navigate()` is a function declared in the `other_window.html`. + child.navigate(); + } + + promise_test(async (t) => { + await childLoaded; + + if (test_driver) { + test_driver.click(document.getElementById("button")); + } + + new PerformanceObserver((list, observer) => t.step(() => { + observer.disconnect(); + assert_unreached("Parent window should not detect a soft-navigation."); + })).observe({ type: "soft-navigation" }); + + child.getNextSoftNavEntry().then((entry) => { + assert_unreached("Child window should not detect a soft-navigation."); + }); + + await new Promise(resolve => t.step_timeout(resolve, 2000)); + + }, "Opening a new window and updating a URL in it shouldn't crash"); + </script> + </body> +</html> diff --git a/tests/wpt/tests/speculation-rules/prefetch/no-prefetch-for-post.https.html b/tests/wpt/tests/speculation-rules/prefetch/no-prefetch-for-post.https.html new file mode 100644 index 00000000000..7739f4f8c71 --- /dev/null +++ b/tests/wpt/tests/speculation-rules/prefetch/no-prefetch-for-post.https.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/utils.js"></script> +<script src="../resources/utils.js"></script> +<script src="resources/utils.sub.js"></script> +<script> + setup(() => assertSpeculationRulesIsSupported()); + + promise_test(async t => { + let agent = await spawnWindow(t); + let nextUrl = agent.getExecutorURL({ executor: 'post-navigation-handler.py', protocol: 'https', page: 2 }); + await agent.forceSinglePrefetch(nextUrl); + + await agent.execute_script(async (nextUrl) => { + window.executor.suspend(() => { + navigate_by_form_generated_post(nextUrl); + }); + }, [nextUrl]); + + assert_not_prefetched(await agent.getRequestHeaders()); + }, "post navigations should not use cached prefetch"); +</script> diff --git a/tests/wpt/tests/speculation-rules/prefetch/resources/executor.sub.html b/tests/wpt/tests/speculation-rules/prefetch/resources/executor.sub.html index bb2d58dc9c9..b89c45e4f5c 100644 --- a/tests/wpt/tests/speculation-rules/prefetch/resources/executor.sub.html +++ b/tests/wpt/tests/speculation-rules/prefetch/resources/executor.sub.html @@ -82,6 +82,13 @@ async function start_non_eager_prefetch_on_pointerdown(id) { await new test_driver.Actions().addPointer("mouse").pointerMove(0, 0, {origin: target}).pointerDown().pointerMove(0, 0).pointerUp().send(); } +async function navigate_by_form_generated_post(url) { + let form = document.createElement('form'); + form.method = 'POST'; + form.action = url; + document.body.appendChild(form); + form.submit(); +} // The fetch request's URL sent to the server. window.requestUrl = reverse_html_escape( diff --git a/tests/wpt/tests/speculation-rules/prefetch/resources/post-navigation-handler.py b/tests/wpt/tests/speculation-rules/prefetch/resources/post-navigation-handler.py new file mode 100644 index 00000000000..1749517710e --- /dev/null +++ b/tests/wpt/tests/speculation-rules/prefetch/resources/post-navigation-handler.py @@ -0,0 +1,10 @@ +import os +from wptserve.pipes import template + +# This is used only to accept POST navigations. +def main(request, response): + response.headers.set(b"Content-Type", b"text/html") + response.headers.set(b"Cache-Control", b"no-store") + response.content = template( + request, + open(os.path.join(os.path.dirname(__file__), "executor.sub.html"), "rb").read())
\ No newline at end of file diff --git a/tests/wpt/tests/speculation-rules/prerender/headers.https.html b/tests/wpt/tests/speculation-rules/prerender/headers.https.html new file mode 100644 index 00000000000..2ef6b5ce072 --- /dev/null +++ b/tests/wpt/tests/speculation-rules/prerender/headers.https.html @@ -0,0 +1,159 @@ +<!DOCTYPE html> +<title>Sec-Purpose header on prerendered page</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"></script> +<script src="../resources/utils.js"></script> +<script src="resources/utils.js"></script> + +<body> +<script> +setup(() => assertSpeculationRulesIsSupported()); + +promise_test(async () => { + const rcHelper = new RemoteContextHelper(); + const referrerRC = await rcHelper.addWindow(undefined, { features: 'noopener' }); + const prerenderedRC = await addPrerenderRC(referrerRC); + + const prerenderedHeaders = await prerenderedRC.getRequestHeaders(); + assertHeaders(prerenderedHeaders, true, true, 'prerendered page'); + + const iframeRC = await prerenderedRC.addIframe(); + const iframeHeaders = await iframeRC.getRequestHeaders(); + assertHeaders(iframeHeaders, true, false, 'iframe'); + + // No test for cross-origin iframe, since those requests are delayed until + // after activation. See below. + + const imageHeaders = await insertImageAndGetRequestHeaders(prerenderedRC); + assertHeaders(imageHeaders, true, false, 'image'); + + const crossOriginImageHeaders = await insertImageAndGetRequestHeaders( + prerenderedRC, + get_host_info().HTTPS_REMOTE_ORIGIN + ); + assertHeaders(crossOriginImageHeaders, true, false, 'cross-origin image'); + + const fetchHeaders = await doFetchAndGetRequestHeaders(prerenderedRC); + assertHeaders(fetchHeaders, true, false, 'fetch'); + + const crossOriginFetchHeaders = await doFetchAndGetRequestHeaders( + prerenderedRC, + get_host_info().HTTPS_REMOTE_ORIGIN + ); + assertHeaders(crossOriginFetchHeaders, true, false, 'cross-origin fetch'); + + const navigatedToRC = await prerenderedRC.navigateToNew(); + const navigatedToHeaders = await navigatedToRC.getRequestHeaders(); + assertHeaders(navigatedToHeaders, true, false, 'navigated-to page'); +}, 'Headers before activation, including prerendered page navigation'); + +promise_test(async () => { + const rcHelper = new RemoteContextHelper(); + const referrerRC = await rcHelper.addWindow(undefined, { features: 'noopener' }); + const prerenderedRC = await addPrerenderRC(referrerRC); + + // Add the iframe now, but only check its headers after activation. + const crossOriginIframeBeforeActivationRC = await prerenderedRC.addIframe({ origin: 'HTTPS_REMOTE_ORIGIN' }); + + await activatePrerenderRC(referrerRC, prerenderedRC); + + const crossOriginIframeBeforeActivationHeaders = await crossOriginIframeBeforeActivationRC.getRequestHeaders(); + assertHeaders(crossOriginIframeBeforeActivationHeaders, true, false, 'cross-origin iframe before activation'); + + const iframeRC = await prerenderedRC.addIframe(); + const iframeHeaders = await iframeRC.getRequestHeaders(); + assertHeaders(iframeHeaders, false, false, 'post-activation iframe'); + + const imageHeaders = await insertImageAndGetRequestHeaders(prerenderedRC); + assertHeaders(imageHeaders, false, false, 'post-activation image'); + + const crossOriginImageHeaders = await insertImageAndGetRequestHeaders( + prerenderedRC, + get_host_info().HTTPS_REMOTE_ORIGIN + ); + assertHeaders(crossOriginImageHeaders, false, false, 'cross-origin image'); + + const fetchHeaders = await doFetchAndGetRequestHeaders(prerenderedRC); + assertHeaders(fetchHeaders, false, false, 'post-activation fetch'); + + const crossOriginFetchHeaders = await doFetchAndGetRequestHeaders( + prerenderedRC, + get_host_info().HTTPS_REMOTE_ORIGIN + ); + assertHeaders(crossOriginFetchHeaders, false, false, 'cross-origin fetch'); +}, 'Headers after activation (plus cross-origin iframe before activation)'); + +async function insertImageAndGetRequestHeaders(rc, hostname) { + const uuid = token(); + const url = (new URL(`resources/image-with-headers-stash.py?image=${uuid}`, location.href)); + const headersURL = (new URL(`resources/image-with-headers-stash.py?read=${uuid}`, location.href)); + + if (hostname !== undefined) { + url.hostname = hostname; + headersURL.hostname = hostname; + } + + await rc.executeScript(async (url) => { + const img = new Image(); + img.src = url; + const promise = new Promise(resolve => img.onload = resolve); + document.body.append(img); + return promise; + }, [url]); + + const headersJSON = await (await fetch(headersURL)).json(); + assert_not_equals(headersJSON, null, 'image headers should not be null'); + return new Headers(headersJSON); +} + +async function doFetchAndGetRequestHeaders(rc, hostname) { + const uuid = token(); + const url = (new URL(`resources/image-with-headers-stash.py?image=${uuid}`, location.href)); + const headersURL = (new URL(`resources/image-with-headers-stash.py?read=${uuid}`, location.href)); + + if (hostname !== undefined) { + url.hostname = hostname; + headersURL.hostname = hostname; + } + + await rc.executeScript(async (url) => { + return fetch(url, { mode: "cors" }); + }, [url]); + + const headersJSON = await (await fetch(headersURL)).json(); + assert_not_equals(headersJSON, null, 'fetch headers should not be null'); + return new Headers(headersJSON); +} + +function assertHeaders(headers, secPurposeIsPrefetchPrerender, secSpeculationTagsIsPresent, label) { + if (secPurposeIsPrefetchPrerender) { + assert_equals( + headers.get('Sec-Purpose'), + 'prefetch;prerender', + `${label} Sec-Purpose` + ); + } else { + assert_false( + headers.has('Sec-Purpose'), + `${label} Sec-Purpose should not be present` + ); + } + if (secSpeculationTagsIsPresent) { + assert_equals( + headers.get('Sec-Speculation-Tags'), + 'null', + `${label} Sec-Speculation-Tags` + ); + } else { + assert_false( + headers.has('Sec-Speculation-Tags'), + `${label} Sec-Speculation-Tags should not be present` + ); + } +} +</script> diff --git a/tests/wpt/tests/speculation-rules/prerender/resources/image-with-headers-stash.py b/tests/wpt/tests/speculation-rules/prerender/resources/image-with-headers-stash.py new file mode 100644 index 00000000000..dcb8838d4a1 --- /dev/null +++ b/tests/wpt/tests/speculation-rules/prerender/resources/image-with-headers-stash.py @@ -0,0 +1,45 @@ +# Supports two operations: +# - ?image=uuid: Returns an image, and records the request headers that were +# used to get that image. +# - ?read=uuid: Returns the request headers in the stash keyed by a given uuid. + +import os +import json + +from wptserve.utils import isomorphic_decode + +def main(request, response): + if b"image" in request.GET: + uuid = request.GET[b"image"] + + header_pairs = [] + for header_name in request.headers.keys(): + # ensure the header name/value are unicode strings + name = header_name.lower().decode("utf-8") + for header_value in request.headers.get_list(header_name): + value = header_value.decode("utf-8") + header_pairs.append([name, value]) + + request_headers = json.dumps(header_pairs) + request.server.stash.put(uuid, request_headers) + + # Return a basic image. + response_headers = [ + (b"Content-Type", b"image/png"), + (b"Access-Control-Allow-Origin", b"*") + ] + image_path = os.path.join( + os.path.dirname(isomorphic_decode(__file__)), + u"../../../common/square.png" + ) + return (200, response_headers, open(image_path, mode='rb').read()) + + elif b"read" in request.GET: + uuid = request.GET[b"read"] + stash_value = request.server.stash.take(uuid) + + if stash_value is None: + stash_value = "null" + return (200, [(b"Content-Type", b"application/json")], str(stash_value)) + + return (404 , [], "Not found") diff --git a/tests/wpt/tests/svg/embedded/image-modify-href-4.svg b/tests/wpt/tests/svg/embedded/image-modify-href-4.svg new file mode 100644 index 00000000000..f7e550e5def --- /dev/null +++ b/tests/wpt/tests/svg/embedded/image-modify-href-4.svg @@ -0,0 +1,30 @@ +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:h="http://www.w3.org/1999/xhtml" width="200" height="200" class="reftest-wait" onload="test()"> + <metadata> + <title>modifying xlink:href on an SVG image</title> + <h:link rel="match" href="reference/green-rect-100x100.svg"/> + </metadata> + <script href="/common/reftest-wait.js"></script> + <script href="/common/rendering-utils.js"></script> + <script> + const SVG_NS = "http://www.w3.org/2000/svg"; + + async function test() { + await waitForAtLeastOneFrame(); + + const doc = document.implementation.createDocument(SVG_NS, "svg"); + + const image = doc.createElementNS(SVG_NS, "image"); + image.setAttribute("width", 100); + image.setAttribute("height", 100); + image.setAttribute("href", "reference/green-rect-100x100.svg"); + doc.documentElement.appendChild(image); + + document.documentElement.appendChild(document.adoptNode(image)); + + await waitForAtLeastOneFrame(); + takeScreenshot(); + } + </script> +</svg> diff --git a/tests/wpt/tests/tools/third_party_modified/mozlog/mozlog/handlers/base.py b/tests/wpt/tests/tools/third_party_modified/mozlog/mozlog/handlers/base.py index 7cea14c7a44..707b539ec76 100644 --- a/tests/wpt/tests/tools/third_party_modified/mozlog/mozlog/handlers/base.py +++ b/tests/wpt/tests/tools/third_party_modified/mozlog/mozlog/handlers/base.py @@ -18,7 +18,7 @@ class BaseHandler(object): def __init__(self, inner): self.message_handler = MessageHandler() if hasattr(inner, "message_handler"): - self.message_handler.wrapped.append(inner) + self.message_handler.wrapped.append(inner.message_handler) class LogLevelFilter(BaseHandler): diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py index 7bb2e57d417..d0cd7411af0 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/firefox_android.py @@ -381,6 +381,9 @@ class FirefoxAndroidBrowser(Browser): class FirefoxAndroidWdSpecBrowser(FirefoxWdSpecBrowser): def __init__(self, logger, config=None, device_serial=None, adb_binary=None, **kwargs): + if "profile_creator_cls" not in kwargs: + kwargs["profile_creator_cls"] = ProfileCreator + super().__init__(logger, config=config, **kwargs) self.config = config diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/headless_shell.py b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/headless_shell.py index b6f7a40f8a9..ccd5620365a 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/headless_shell.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/headless_shell.py @@ -3,6 +3,7 @@ from .base import require_arg from .base import get_timeout_multiplier # noqa: F401 from .chrome import ChromeBrowser # noqa: F401 +from .chrome import browser_kwargs as browser_kwargs # noqa: F401 from .chrome import executor_kwargs as chrome_executor_kwargs from ..executors.base import WdspecExecutor # noqa: F401 from ..executors.executorchrome import ( # noqa: F401 @@ -35,13 +36,6 @@ def check_args(**kwargs): require_arg(kwargs, "webdriver_binary") -def browser_kwargs(logger, test_type, run_info_data, config, **kwargs): - return {"binary": kwargs["binary"], - "webdriver_binary": kwargs["webdriver_binary"], - "webdriver_args": kwargs.get("webdriver_args"), - "debug_info": kwargs["debug_info"]} - - def executor_kwargs(logger, test_type, test_environment, run_info_data, subsuite, **kwargs): executor_kwargs = chrome_executor_kwargs(logger, test_type, test_environment, run_info_data, diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servo.py b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servo.py index 266aec8fced..49a2613ff12 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servo.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servo.py @@ -37,7 +37,8 @@ def check_args(**kwargs): require_arg(kwargs, "binary") -def browser_kwargs(logger, test_type, run_info_data, config, **kwargs): +def browser_kwargs(logger, test_type, run_info_data, config, subsuite, **kwargs): + kwargs["binary_args"].extend(subsuite.config.get("binary_args", [])) return { "binary": kwargs["binary"], "debug_info": kwargs["debug_info"], @@ -68,7 +69,7 @@ def env_options(): def update_properties(): - return ["debug", "os", "processor"], {"os": ["version"], "processor": ["bits"]} + return ["debug", "os", "processor", "subsuite"], {"os": ["version"], "processor": ["bits"]} class ServoBrowser(NullBrowser): diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servodriver.py b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servodriver.py index 5011a8fd859..a8aa5ae001b 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servodriver.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/servodriver.py @@ -39,7 +39,8 @@ def check_args(**kwargs): require_arg(kwargs, "binary") -def browser_kwargs(logger, test_type, run_info_data, config, **kwargs): +def browser_kwargs(logger, test_type, run_info_data, config, subsuite, **kwargs): + kwargs["binary_args"].extend(subsuite.config.get("binary_args", [])) return { "binary": kwargs["binary"], "binary_args": kwargs["binary_args"], @@ -67,7 +68,7 @@ def env_options(): def update_properties(): - return (["debug", "os", "processor"], {"os": ["version"], "processor": ["bits"]}) + return (["debug", "os", "processor", "subsuite"], {"os": ["version"], "processor": ["bits"]}) def write_hosts_file(config): diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py index 1e588d5bfbf..3284e6c8091 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py @@ -304,6 +304,10 @@ class ChromeDriverTestharnessExecutor(WebDriverTestharnessExecutor): test_window = self.protocol.testharness.persistent_test_window = None if not test_window: test_window = super().get_or_create_test_window(protocol) + if self.reuse_window: + self.logger.info(f"Created new test window {test_window}") + # Without `--reuse-window`, each testharness test always creates a + # new window, so tracing that event is not interesting. if self.reuse_window: self.protocol.testharness.persistent_test_window = test_window return test_window diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/testrunner.py b/tests/wpt/tests/tools/wptrunner/wptrunner/testrunner.py index 19c814bb6c9..be310944fd8 100644 --- a/tests/wpt/tests/tools/wptrunner/wptrunner/testrunner.py +++ b/tests/wpt/tests/tools/wptrunner/wptrunner/testrunner.py @@ -313,7 +313,7 @@ class TestSource: if not self.current_group.group or len(self.current_group.group) == 0: try: self.current_group = self.test_queue.get() - self.logger.debug(f"Got new test group subsuite:{self.current_group[1]} " + self.logger.debug(f"Got new test group subsuite:{self.current_group[1]!r} " f"test_type:{self.current_group[2]}") except Empty: return testloader.TestGroup(None, None, None, None) @@ -473,11 +473,11 @@ class TestRunnerManager(threading.Thread): if skipped_tests: self.logger.critical( - f"Tests left in the queue: {subsuite}:{skipped_tests[0].id!r} " + f"Tests left in the queue: {subsuite!r}:{skipped_tests[0].id!r} " f"and {len(skipped_tests) - 1} others" ) for test in skipped_tests[1:]: - self.logger.debug(f"Test left in the queue: {subsuite}:{test.id!r}") + self.logger.debug(f"Test left in the queue: {subsuite!r}:{test.id!r}") force_stop = (not isinstance(self.state, RunnerManagerState.stop) or self.state.force_stop) @@ -900,7 +900,7 @@ class TestRunnerManager(threading.Thread): if test is None: return RunnerManagerState.stop(force_stop) if subsuite != self.state.subsuite: - self.logger.info(f"Restarting browser for new subsuite:{subsuite}") + self.logger.info(f"Restarting browser for new subsuite:{subsuite!r}") restart = True elif self.restart_on_new_group and test_group is not self.state.test_group: self.logger.info("Restarting browser for new test group") diff --git a/tests/wpt/tests/trusted-types/block-text-node-insertion-into-script-element.html b/tests/wpt/tests/trusted-types/block-text-node-insertion-into-script-element.html index 65b40b933ff..1a1256d05a8 100644 --- a/tests/wpt/tests/trusted-types/block-text-node-insertion-into-script-element.html +++ b/tests/wpt/tests/trusted-types/block-text-node-insertion-into-script-element.html @@ -49,12 +49,12 @@ assert_equals(s.text, ""); // Try to insertAdjacentText into the <script>, starting from the <p> - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("beforebegin", "postMessage('beforebegin should be blocked', '*');") ); assert_true(s.text.includes("postMessage")); - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("afterend", "postMessage('afterend should be blocked', '*');") ); @@ -74,12 +74,12 @@ container.appendChild(s); // Try to insertAdjacentText into the <script>, starting from the <p> - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("beforebegin", "postMessage('beforebegin should be blocked', '*');") ); assert_true(s.textContent.includes("postMessage")); - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("afterend", "postMessage('afterend should be blocked', '*');") ); @@ -94,7 +94,7 @@ let text = document.createTextNode("postMessage('appendChild with a " + "text node should be blocked', '*');"); s.appendChild(text); - await checkMessage(_ => container.appendChild(s)); + await checkMessage(t, _ => container.appendChild(s)); }, "Regression test: Bypass via appendChild into off-document script element."); // Variant: Create a <script> element and insert it into the document. Then @@ -106,7 +106,7 @@ container.appendChild(s); let text = document.createTextNode("postMessage('appendChild with a live " + "text node should be blocked', '*');"); - await checkMessage(_ => s.appendChild(text)); + await checkMessage(t, _ => s.appendChild(text)); }, "Regression test: Bypass via appendChild into live script element."); promise_test(async t => { @@ -150,7 +150,7 @@ let text = document.createTextNode("postMessage('default', '*');"); s.appendChild(text); await no_trusted_type_violation_for(async _ => - await checkMessage(_ => container.appendChild(s), 1) + await checkMessage(t, _ => container.appendChild(s), 1) ); assert_array_equals(seenSinks, ["HTMLScriptElement text"]); }, "Test that default policy applies."); @@ -158,10 +158,22 @@ promise_test(async t => { t.add_cleanup(clearSeenSinks); let s = createScriptElement(); + s.setAttribute("type", "module") + let text = document.createTextNode("postMessage('default', '*');"); + s.appendChild(text); + await no_trusted_type_violation_for(async _ => + await checkMessage(t, _ => container.appendChild(s), 1) + ); + assert_array_equals(seenSinks, ["HTMLScriptElement text"]); + }, "Test that default policy applies to module script."); + + promise_test(async t => { + t.add_cleanup(clearSeenSinks); + let s = createScriptElement(); let text = document.createTextNode("fail"); s.appendChild(text); await trusted_type_violation_without_exception_for(async _ => - await checkMessage(_ => container.appendChild(s), 0) + await checkMessage(t, _ => container.appendChild(s), 0) ); assert_array_equals(seenSinks, ["HTMLScriptElement text"]); }, "Test a failing default policy."); diff --git a/tests/wpt/tests/trusted-types/block-text-node-insertion-into-svg-script-element.html b/tests/wpt/tests/trusted-types/block-text-node-insertion-into-svg-script-element.html index f4ff2435035..18c6af8f5ef 100644 --- a/tests/wpt/tests/trusted-types/block-text-node-insertion-into-svg-script-element.html +++ b/tests/wpt/tests/trusted-types/block-text-node-insertion-into-svg-script-element.html @@ -49,12 +49,12 @@ container.appendChild(s); // Try to insertAdjacentText into the <script>, starting from the <p> - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("beforebegin", "postMessage('beforebegin should be blocked', '*');") ); assert_true(s.textContent.includes("postMessage")); - await checkMessage(_ => + await checkMessage(t, _ => p.insertAdjacentText("afterend", "postMessage('afterend should be blocked', '*');") ); @@ -69,7 +69,7 @@ let text = document.createTextNode("postMessage('appendChild with a " + "text node should be blocked', '*');"); s.appendChild(text); - await checkMessage(_ => container.appendChild(s)); + await checkMessage(t, _ => container.appendChild(s)); }, "Regression test: Bypass via appendChild into off-document script element. svg:script"); // Variant: Create a <script> element and insert it into the document. Then @@ -81,7 +81,7 @@ container.appendChild(s); let text = document.createTextNode("postMessage('appendChild with a live " + "text node should be blocked', '*');"); - await checkMessage(_ => s.appendChild(text)); + await checkMessage(t, _ => s.appendChild(text)); }, "Regression test: Bypass via appendChild into live script element. svg:script"); promise_test(async t => { @@ -125,7 +125,7 @@ let text = document.createTextNode("postMessage('default', '*');"); s.appendChild(text); await no_trusted_type_violation_for(async _ => - await checkMessage(_ => container.appendChild(s), 1) + await checkMessage(t, _ => container.appendChild(s), 1) ); assert_array_equals(seenSinks, ["SVGScriptElement text"]); }, "Test that default policy applies. svg:script"); @@ -133,10 +133,22 @@ promise_test(async t => { t.add_cleanup(clearSeenSinks); let s = createScriptElement(); + s.setAttribute("type", "module"); + let text = document.createTextNode("postMessage('default', '*');"); + s.appendChild(text); + await no_trusted_type_violation_for(async _ => + await checkMessage(t, _ => container.appendChild(s), 1) + ); + assert_array_equals(seenSinks, ["SVGScriptElement text"]); + }, "Test that default policy applies with module script. svg:script"); + + promise_test(async t => { + t.add_cleanup(clearSeenSinks); + let s = createScriptElement(); let text = document.createTextNode("fail"); s.appendChild(text); await trusted_type_violation_without_exception_for(async _ => - await checkMessage(_ => container.appendChild(s), 0) + await checkMessage(t, _ => container.appendChild(s), 0) ); assert_array_equals(seenSinks, ["SVGScriptElement text"]); }, "Test a failing default policy. svg:script"); diff --git a/tests/wpt/tests/trusted-types/resources/block-text-node-insertion.js b/tests/wpt/tests/trusted-types/resources/block-text-node-insertion.js index e9797756417..dd85483a44f 100644 --- a/tests/wpt/tests/trusted-types/resources/block-text-node-insertion.js +++ b/tests/wpt/tests/trusted-types/resources/block-text-node-insertion.js @@ -14,10 +14,13 @@ // - includes "count": Count these, and later check against expect_count. // - includes "done": Unregister the event handler and finish the test. // - all else: Reject, as this is probably an error in the test. - function checkMessage(fn, expect_count) { + function checkMessage(t, fn, expect_count) { return new Promise((resolve, reject) => { let count = 0; globalThis.addEventListener("message", function handler(e) { + t.add_cleanup(() => { + globalThis.removeEventListener("message", handler); + }); if (e.data.includes("block")) { reject(`'block' received (${e.data})`); } else if (e.data.includes("count")) { @@ -35,6 +38,6 @@ } }); fn(); - postMessage("done", "*"); + requestAnimationFrame(_ => requestAnimationFrame(_ => postMessage("done", "*"))); }); } diff --git a/tests/wpt/tests/ua-client-hints/WEB_FEATURES.yml b/tests/wpt/tests/ua-client-hints/WEB_FEATURES.yml new file mode 100644 index 00000000000..2d331cf4060 --- /dev/null +++ b/tests/wpt/tests/ua-client-hints/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: ua-client-hints + files: "**" diff --git a/tests/wpt/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html b/tests/wpt/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html deleted file mode 100644 index 2da0a389e2e..00000000000 --- a/tests/wpt/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html +++ /dev/null @@ -1,32 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<title> ProcessingInstruction.data and DOMCharacterDataModified event </title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -<div id=log></div> - -<iframe id="helper" style="display: none"></iframe> - -<script> - var description = "Test Description: " + - "DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified, " + - "but the node itself has not been inserted or deleted. The proximal event target of this " + - "event shall be the ProcessingInstruction node."; - - var t = async_test(description); - - var HELPER = document.getElementById("helper"); - - HELPER.onload = t.step_func(function() - { - assert_true(HELPER.contentWindow.TestResult); - t.done(); - }); - - HELPER.src = "./support/ProcessingInstruction.DOMCharacterDataModified.xml"; -</script> -</body> -</html> diff --git a/tests/wpt/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html b/tests/wpt/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html deleted file mode 100644 index e5064d8d46c..00000000000 --- a/tests/wpt/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html +++ /dev/null @@ -1,26 +0,0 @@ -<!DOCTYPE html> -<title>MutationEvent: DOMNodeInserted Event Type</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<div id=log></div> - -<div id="target" style="display: none"></div> - -<script> -var EVENT = "DOMNodeInserted"; -var TARGET; -var NODE; - -var t = async_test("Test Description: DOMNodeInserted event fires when a node has been added as a child of another node."); - -TARGET = document.getElementById("target"); - -TARGET.addEventListener(EVENT, t.step_func(function(evt) -{ - assert_equals(evt.type, EVENT); - t.done(); -}), true); - -NODE = document.createElement("INPUT"); -TARGET.appendChild(NODE); -</script> diff --git a/tests/wpt/tests/urlpattern/resources/urlpattern-generate-test-data.json b/tests/wpt/tests/urlpattern/resources/urlpattern-generate-test-data.json new file mode 100644 index 00000000000..c118f0a73b5 --- /dev/null +++ b/tests/wpt/tests/urlpattern/resources/urlpattern-generate-test-data.json @@ -0,0 +1,116 @@ +[ + { + "pattern": { "pathname": "/foo" }, + "component": "invalid", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/foo" }, + "component": "pathname", + "groups": {}, + "expected": "/foo" + }, + { + "pattern": { "pathname": "/:foo" }, + "component": "pathname", + "groups": { "foo": "bar" }, + "expected": "/bar" + }, + { + "pattern": { "pathname": "/:foo" }, + "component": "pathname", + "groups": { "foo": "🍅" }, + "expected": "/%F0%9F%8D%85" + }, + { + "pattern": { "hostname": "{:foo}.example.com" }, + "component": "hostname", + "groups": { "foo": "🍅" }, + "expected": "xn--fi8h.example.com" + }, + { + "pattern": { "pathname": "/:foo" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/foo/:bar" }, + "component": "pathname", + "groups": { "bar": "baz" }, + "expected": "/foo/baz" + }, + { + "pattern": { "pathname": "/foo:bar" }, + "component": "pathname", + "groups": { "bar": "baz" }, + "expected": "/foobaz" + }, + { + "pattern": { "pathname": "/:foo/:bar" }, + "component": "pathname", + "groups": { "foo": "baz", "bar": "qux" }, + "expected": "/baz/qux" + }, + { + "pattern": "https://example.com/:foo", + "component": "pathname", + "groups": { "foo": " " }, + "expected": "/%20" + }, + { + "pattern": "original-scheme://example.com/:foo", + "component": "pathname", + "groups": { "foo": " " }, + "expected": "/ " + }, + { + "pattern": { "pathname": "/:foo" }, + "component": "pathname", + "groups": { "foo": "bar/baz" }, + "expected": null + }, + { + "pattern": { "pathname": "*" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/{foo}+" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/{foo}?" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/{foo}*" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/(regexp)" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "pathname": "/([^\\/]+?)" }, + "component": "pathname", + "groups": {}, + "expected": null + }, + { + "pattern": { "port": "([^\\:]+?)" }, + "component": "port", + "groups": {}, + "expected": null + } +] diff --git a/tests/wpt/tests/urlpattern/urlpattern-generate.tentative.any.js b/tests/wpt/tests/urlpattern/urlpattern-generate.tentative.any.js new file mode 100644 index 00000000000..1f6962942d8 --- /dev/null +++ b/tests/wpt/tests/urlpattern/urlpattern-generate.tentative.any.js @@ -0,0 +1,26 @@ +// META: global=window,worker + +function runTests(data) { + for (let entry of data) { + test(function () { + const pattern = new URLPattern(entry.pattern); + + if (entry.expected === null) { + assert_throws_js(TypeError, _ => pattern.generate(entry.component, entry.groups), + 'generate() should fail with TypeError'); + return; + } + + const result = pattern.generate(entry.component, entry.groups); + assert_equals(result, entry.expected); + }, `Pattern: ${JSON.stringify(entry.pattern)} ` + + `Component: ${entry.component} ` + + `Groups: ${JSON.stringify(entry.groups)}`); + } +} + +promise_test(async function () { + const response = await fetch('resources/urlpattern-generate-test-data.json'); + const data = await response.json(); + runTests(data); +}, 'Loading data...'); diff --git a/tests/wpt/tests/webnn/conformance_tests/cumulative_sum.https.any.js b/tests/wpt/tests/webnn/conformance_tests/cumulative_sum.https.any.js index 85e1ab427d2..34a625152b2 100644 --- a/tests/wpt/tests/webnn/conformance_tests/cumulative_sum.https.any.js +++ b/tests/wpt/tests/webnn/conformance_tests/cumulative_sum.https.any.js @@ -26,13 +26,14 @@ const getCumulativeSumPrecisionTolerance = (graphResources) => { const axis = args[1][Object.keys(args[1])[0]]; let tolerance = inputShape[axis] - 1; - const toleranceValueDict = {float32: tolerance, int32: 0}; + const toleranceValueDict = {float32: tolerance, float16: tolerance, int32: 0}; const expectedDataType = getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs); return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]}; }; const cumulativeSumTests = [ + // float32 tests { 'name': 'cumulativeSum with float32 input and default options.', 'graph': { @@ -51,7 +52,7 @@ const cumulativeSumTests = [ 'name': 'cumulativeSum', 'arguments': [ {'input': 'cumulativeSumInput'}, - {'axis': 3}, + {'axis': 3} ], 'outputs': 'cumulativeSumOutput' }], @@ -68,32 +69,41 @@ const cumulativeSumTests = [ } }, { - 'name': 'cumulativeSum with int32 input and axis = 2.', + 'name': 'cumulativeSum with float32 input and set exclusive to true.', 'graph': { 'inputs': { 'cumulativeSumInput': { - 'data': [2, 1, 3, 5, 3, 8, 7, 3, 9, 6, 2, 4], - 'descriptor': {shape: [1, 1, 3, 4], dataType: 'int32'} + 'data': [ + 60.42374038696289, -86.92247772216797, -19.496112823486328, + -15.150615692138672, 13.455190658569336, 45.433597564697266, + 61.082862854003906, 70.71882629394531, -31.278579711914062, + 56.08354187011719, 38.992767333984375, -3.27536940574646 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float32'} } }, 'operators': [{ 'name': 'cumulativeSum', 'arguments': [ {'input': 'cumulativeSumInput'}, - {'axis': 2}, + {'axis': 3}, + {'options': {'exclusive': true}} ], 'outputs': 'cumulativeSumOutput' }], 'expectedOutputs': { 'cumulativeSumOutput': { - 'data': [2, 1, 3, 5, 5, 9, 10, 8, 14, 15, 12, 12], - 'descriptor': {shape: [1, 1, 3, 4], dataType: 'int32'} + 'data': [ + 0.0, 60.4237404, -26.4987373, -45.994854, 0.0, 13.4551907, + 58.8887863, 119.9716568, 0.0, -31.2785797, 24.8049622, 63.7977295 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float32'} } } } }, { - 'name': 'cumulativeSum with float32 input and set exclusive to true.', + 'name': 'cumulativeSum with float32 input and set reversed to true.', 'graph': { 'inputs': { 'cumulativeSumInput': { @@ -111,56 +121,141 @@ const cumulativeSumTests = [ 'arguments': [ {'input': 'cumulativeSumInput'}, {'axis': 3}, - {'options': {'exclusive': true}}, + {'options': {'reversed': true}} ], 'outputs': 'cumulativeSumOutput' }], 'expectedOutputs': { 'cumulativeSumOutput': { 'data': [ - 0.0, 60.4237404, -26.4987373, -45.994854, 0.0, 13.4551907, - 58.8887863, 119.9716568, 0.0, -31.2785797, 24.8049622, 63.7977295 + -61.1454659, -121.5692139, -34.6467285, -15.1506157, 190.6904907, + 177.2352905, 131.8016968, 70.7188263, 60.5223618, 91.8009415, + 35.7173996, -3.2753694 ], 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float32'} } } } }, + + // float16 tests { - 'name': 'cumulativeSum with float32 input and set reversed to true.', + 'name': 'cumulativeSum with float16 input and default options.', 'graph': { 'inputs': { 'cumulativeSumInput': { 'data': [ - 60.42374038696289, -86.92247772216797, -19.496112823486328, - -15.150615692138672, 13.455190658569336, 45.433597564697266, - 61.082862854003906, 70.71882629394531, -31.278579711914062, - 56.08354187011719, 38.992767333984375, -3.27536940574646 + 60.4375, -86.9375, -19.5, -15.1484375, 13.453125, 45.4375, 61.09375, + 70.75, -31.28125, 56.09375, 39, -3.275390625 ], - 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float32'} + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'cumulativeSum', + 'arguments': [{'input': 'cumulativeSumInput'}, {'axis': 3}], + 'outputs': 'cumulativeSumOutput' + }], + 'expectedOutputs': { + 'cumulativeSumOutput': { + 'data': [ + 60.4375, -26.5, -46, -61.15625, 13.453125, 58.875, 120, 190.75, + -31.28125, 24.8125, 63.8125, 60.53125 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} + } + } + } + }, + { + 'name': 'cumulativeSum with float16 input and set exclusive to true.', + 'graph': { + 'inputs': { + 'cumulativeSumInput': { + 'data': [ + 60.4375, -86.9375, -19.5, -15.1484375, 13.453125, 45.4375, 61.09375, + 70.75, -31.28125, 56.09375, 39, -3.275390625 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} } }, 'operators': [{ 'name': 'cumulativeSum', 'arguments': [ - {'input': 'cumulativeSumInput'}, - {'axis': 3}, - {'options': {'reversed': true}}, + {'input': 'cumulativeSumInput'}, {'axis': 3}, + {'options': {'exclusive': true}} ], 'outputs': 'cumulativeSumOutput' }], 'expectedOutputs': { 'cumulativeSumOutput': { 'data': [ - -61.1454659, -121.5692139, -34.6467285, -15.1506157, 190.6904907, - 177.2352905, 131.8016968, 70.7188263, 60.5223618, 91.8009415, - 35.7173996, -3.2753694 + 0, 60.4375, -26.5, -46, 0, 13.453125, 58.875, 120, 0, -31.28125, + 24.8125, 63.8125 ], - 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float32'} + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} } } } }, + { + 'name': 'cumulativeSum with float16 input and set reversed to true.', + 'graph': { + 'inputs': { + 'cumulativeSumInput': { + 'data': [ + 60.4375, -86.9375, -19.5, -15.1484375, 13.453125, 45.4375, 61.09375, + 70.75, -31.28125, 56.09375, 39, -3.275390625 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'cumulativeSum', + 'arguments': [ + {'input': 'cumulativeSumInput'}, {'axis': 3}, + {'options': {'reversed': true}} + ], + 'outputs': 'cumulativeSumOutput' + }], + 'expectedOutputs': { + 'cumulativeSumOutput': { + 'data': [ + -61.15625, -121.5625, -34.65625, -15.1484375, 190.75, 177.25, + 131.875, 70.75, 60.53125, 91.8125, 35.71875, -3.275390625 + ], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'float16'} + } + } + } + }, + + // int32 tests + { + 'name': 'cumulativeSum with int32 input and axis = 2.', + 'graph': { + 'inputs': { + 'cumulativeSumInput': { + 'data': [2, 1, 3, 5, 3, 8, 7, 3, 9, 6, 2, 4], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'int32'} + } + }, + 'operators': [{ + 'name': 'cumulativeSum', + 'arguments': [ + {'input': 'cumulativeSumInput'}, + {'axis': 2} + ], + 'outputs': 'cumulativeSumOutput' + }], + 'expectedOutputs': { + 'cumulativeSumOutput': { + 'data': [2, 1, 3, 5, 5, 9, 10, 8, 14, 15, 12, 12], + 'descriptor': {shape: [1, 1, 3, 4], dataType: 'int32'} + } + } + } + } ]; if (navigator.ml) { diff --git a/tests/wpt/tests/webnn/conformance_tests/linear.https.any.js b/tests/wpt/tests/webnn/conformance_tests/linear.https.any.js index 9231aaf9eca..1f13fe170d4 100644 --- a/tests/wpt/tests/webnn/conformance_tests/linear.https.any.js +++ b/tests/wpt/tests/webnn/conformance_tests/linear.https.any.js @@ -19,6 +19,7 @@ // MLOperand linear(MLOperand input, optional MLLinearOptions options = {}); const linearTests = [ + // float32 tests { 'name': 'linear float32 1D constant tensor default options', 'graph': { @@ -542,6 +543,474 @@ const linearTests = [ } } } + }, + + // float16 tests + { + 'name': 'linear float16 1D constant tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [24], dataType: 'float16'}, + 'constant': true + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [24], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 0D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [-1.1220703125], + 'descriptor': {shape: [], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [-1.1220703125], + 'descriptor': {shape: [], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 1D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [24], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [24], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 2D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [4, 6], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [4, 6], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 3D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 3, 4], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 4D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': 'linear float16 5D tensor default options', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 1, 4, 1, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [{'input': 'linearInput'}], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 1, 4, 1, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 4D tensor specified options.alpha and default options.beta', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -1.1220703125, -6.60546875, -1.955078125, -4.59765625, + 4.234375, 3.09765625, 3.74609375, -4.48828125, + 6.40625, -4.35546875, -5.8203125, 3.720703125, + -6.33203125, 8.578125, -6.765625, 6.43359375, + -9.7109375, 2.642578125, 5.21484375, 9.65625, + -8.71875, -0.453369140625, 9.9921875, -6.46875 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, {'options': {'alpha': 7.398793812746618}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -8.3046875, -48.875, -14.46875, -34.03125, 31.328125, + 22.921875, 27.71875, -33.21875, 47.40625, -32.21875, + -43.0625, 27.53125, -46.84375, 63.46875, -50.0625, + 47.59375, -71.875, 19.546875, 38.59375, 71.4375, + -64.5, -3.353515625, 73.9375, -47.875 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 positive 4D tensor specified positive options.beta and default options.alpha', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + 5.09765625, 3.380859375, 8.0546875, 8.078125, 0.470703125, + 5.2421875, 3.828125, 5.37109375, 6.1015625, 3.75, + 0.748046875, 1.8935546875, 1.9052734375, 7.86328125, 4.58203125, + 9.375, 6.5859375, 9.34375, 5.16015625, 0.80615234375, + 9.1328125, 3.193359375, 5.75, 4.11328125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, {'options': {'beta': 5.919095653700928}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + 11.015625, 9.296875, 13.9765625, 14, 6.390625, + 11.1640625, 9.75, 11.2890625, 12.0234375, 9.671875, + 6.66796875, 7.8125, 7.82421875, 13.78125, 10.5, + 15.296875, 12.5078125, 15.265625, 11.078125, 6.7265625, + 15.0546875, 9.109375, 11.671875, 10.03125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 negative 4D tensor specified negative options.beta and default options.alpha', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -5.09765625, -3.380859375, -8.0546875, -8.078125, + -0.470703125, -5.2421875, -3.828125, -5.37109375, + -6.1015625, -3.75, -0.748046875, -1.8935546875, + -1.9052734375, -7.86328125, -4.58203125, -9.375, + -6.5859375, -9.34375, -5.16015625, -0.80615234375, + -9.1328125, -3.193359375, -5.75, -4.11328125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, {'options': {'beta': -5.919095653700928}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -11.015625, -9.296875, -13.9765625, -14, -6.390625, + -11.1640625, -9.75, -11.2890625, -12.0234375, -9.671875, + -6.66796875, -7.8125, -7.82421875, -13.78125, -10.5, + -15.296875, -12.5078125, -15.265625, -11.078125, -6.7265625, + -15.0546875, -9.109375, -11.671875, -10.03125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 positive 4D tensor all options (positive options.alpha and positive options.beta)', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + 5.09765625, 3.380859375, 8.0546875, 8.078125, 0.470703125, + 5.2421875, 3.828125, 5.37109375, 6.1015625, 3.75, + 0.748046875, 1.8935546875, 1.9052734375, 7.86328125, 4.58203125, + 9.375, 6.5859375, 9.34375, 5.16015625, 0.80615234375, + 9.1328125, 3.193359375, 5.75, 4.11328125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, + {'options': {'alpha': 7.398793812746618, 'beta': 5.919095653700928}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + 43.625, 30.9375, 65.5, 65.6875, 9.3984375, 44.71875, + 34.25, 45.65625, 51.0625, 33.65625, 11.453125, 19.921875, + 20.015625, 64.125, 39.8125, 75.3125, 54.65625, 75.0625, + 44.09375, 11.8828125, 73.5, 29.546875, 48.46875, 36.34375 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 positive 4D tensor all options (negative options.alpha and negative options.beta)', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + 5.09765625, 3.380859375, 8.0546875, 8.078125, 0.470703125, + 5.2421875, 3.828125, 5.37109375, 6.1015625, 3.75, + 0.748046875, 1.8935546875, 1.9052734375, 7.86328125, 4.58203125, + 9.375, 6.5859375, 9.34375, 5.16015625, 0.80615234375, + 9.1328125, 3.193359375, 5.75, 4.11328125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, + {'options': {'alpha': -7.398793812746618, 'beta': -5.919095653700928}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -43.625, -30.9375, -65.5, -65.6875, -9.3984375, + -44.71875, -34.25, -45.65625, -51.0625, -33.65625, + -11.453125, -19.921875, -20.015625, -64.125, -39.8125, + -75.3125, -54.65625, -75.0625, -44.09375, -11.8828125, + -73.5, -29.546875, -48.46875, -36.34375 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } + }, + { + 'name': + 'linear float16 negative 4D tensor all options (positive options.alpha and negative options.beta)', + 'graph': { + 'inputs': { + 'linearInput': { + 'data': [ + -5.09765625, -3.380859375, -8.0546875, -8.078125, + -0.470703125, -5.2421875, -3.828125, -5.37109375, + -6.1015625, -3.75, -0.748046875, -1.8935546875, + -1.9052734375, -7.86328125, -4.58203125, -9.375, + -6.5859375, -9.34375, -5.16015625, -0.80615234375, + -9.1328125, -3.193359375, -5.75, -4.11328125 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + }, + 'operators': [{ + 'name': 'linear', + 'arguments': [ + {'input': 'linearInput'}, + {'options': {'alpha': 7.398793812746618, 'beta': -5.919095653700928}} + ], + 'outputs': 'linearOutput' + }], + 'expectedOutputs': { + 'linearOutput': { + 'data': [ + -43.625, -30.9375, -65.5, -65.6875, -9.3984375, + -44.71875, -34.25, -45.65625, -51.0625, -33.65625, + -11.453125, -19.921875, -20.015625, -64.125, -39.8125, + -75.3125, -54.65625, -75.0625, -44.09375, -11.8828125, + -73.5, -29.546875, -48.46875, -36.34375 + ], + 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'} + } + } + } } ]; diff --git a/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js b/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js index ac384c917b3..996a6b472c5 100644 --- a/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js +++ b/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js @@ -141,6 +141,283 @@ const subgraphTests = [ } }, { + 'name': 'dequantizeLinear -> conv2d -> clamp -> quantizeLinear', + 'graph': { + 'inputs': { + 'input': { + 'data': [0.05605664849281311, 0.7114229798316956, 0.6529743671417236], + 'descriptor': {shape: [1, 1, 1, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [-128], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'filter': { + 'data': [2, 3, 4], + 'descriptor': {shape: [1, 1, 1, 3], dataType: 'int8'}, + 'constant': true + }, + 'filterScale': { + 'data': [0.023458752938762234], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'filterZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'bias': { + 'data': [1], + 'descriptor': {shape: [1], dataType: 'int32'}, + 'constant': true + }, + 'biasScale': { + 'data': [0.000091995115004270], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'biasZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int32'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'filter'}, + {'scale': 'filterScale', 'zeroPoint': 'filterZeroPoint'} + ], + 'outputs': 'dequantizedFilter' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'bias'}, + {'scale': 'biasScale', 'zeroPoint': 'biasZeroPoint'} + ], + 'outputs': 'dequantizedBias' + }, + { + 'name': 'conv2d', + 'arguments': [ + {'input': 'dequantizedInput'}, {'filter': 'dequantizedFilter'}, { + 'options': { + 'inputLayout': 'nhwc', + 'bias': 'dequantizedBias', + 'filterLayout': 'ohwi' + } + } + ], + 'outputs': 'conv2dOutput' + }, + { + 'name': 'clamp', + 'arguments': [ + {'input': 'conv2dOutput'}, + {'options': {'minValue': 0, 'maxValue': 6}} + ], + 'outputs': 'clampOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'clampOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedClampOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedClampOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [0.11372549831867218], + 'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'} + } + } + } + }, + { + 'name': 'dequantizeLinear -> conv2d -> relu -> quantizeLinear', + 'graph': { + 'inputs': { + 'input': { + 'data': [0.05605664849281311, 0.7114229798316956, 0.6529743671417236], + 'descriptor': {shape: [1, 1, 1, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [-128], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'filter': { + 'data': [2, 3, 4], + 'descriptor': {shape: [1, 1, 1, 3], dataType: 'int8'}, + 'constant': true + }, + 'filterScale': { + 'data': [0.7114229798316956], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'filterZeroPoint': { + 'data': [-128], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'bias': { + 'data': [1], + 'descriptor': {shape: [1], dataType: 'int32'}, + 'constant': true + }, + 'biasScale': { + 'data': [0.000091995115004270], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'biasZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int32'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'filter'}, + {'scale': 'filterScale', 'zeroPoint': 'filterZeroPoint'} + ], + 'outputs': 'dequantizedFilter' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'bias'}, + {'scale': 'biasScale', 'zeroPoint': 'biasZeroPoint'} + ], + 'outputs': 'dequantizedBias' + }, + { + 'name': 'conv2d', + 'arguments': [ + {'input': 'dequantizedInput'}, {'filter': 'dequantizedFilter'}, { + 'options': { + 'inputLayout': 'nhwc', + 'bias': 'dequantizedBias', + 'filterLayout': 'ohwi' + } + } + ], + 'outputs': 'conv2dOutput' + }, + { + 'name': 'relu', + 'arguments': [ + {'input': 'conv2dOutput'} + ], + 'outputs': 'reluOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'reluOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedReluOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedReluOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [0.49803924560546875], + 'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'} + } + } + } + }, + { 'name': 'quantized element-wise binary add', 'graph': { 'inputs': { @@ -1846,6 +2123,423 @@ const subgraphTests = [ } } }, + { + 'name': 'quantized reduceMax', + 'graph': { + 'inputs': { + 'input': { + 'data': [ + 1.6811466217041016, 0.0479511022567749, 0.33355462551116943, + -0.1988269537687301, -0.0041167140007019, -0.0634240251779556, + ], + 'descriptor': {shape: [2, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'reduceMax', + 'arguments': [{'input': 'dequantizedInput'}, {'options': {'axes': [1]}}], + 'outputs': 'reduceMaxOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'reduceMaxOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedReduceMaxOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedReduceMaxOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.49803924560546875, -0.003921568859368563, + ], + 'descriptor': {shape: [2], dataType: 'float32'} + } + } + } + }, + { + 'name': 'quantized reduceMin', + 'graph': { + 'inputs': { + 'input': { + 'data': [ + 1.6811466217041016, 0.0479511022567749, 0.33355462551116943, + -0.1988269537687301, -0.0041167140007019, -0.0634240251779556, + ], + 'descriptor': {shape: [2, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'reduceMin', + 'arguments': [{'input': 'dequantizedInput'}, {'options': {'axes': [1]}}], + 'outputs': 'reduceMinOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'reduceMinOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedReduceMinOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedReduceMinOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.0470588281750679, -0.20000001788139343, + ], + 'descriptor': {shape: [2], dataType: 'float32'} + } + } + } + }, + { + 'name': 'quantized reduceMean', + 'graph': { + 'inputs': { + 'input': { + 'data': [ + 1.6811466217041016, 0.0479511022567749, 0.33355462551116943, + -0.1988269537687301, -0.0041167140007019, -0.0634240251779556, + ], + 'descriptor': {shape: [2, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'reduceMean', + 'arguments': [{'input': 'dequantizedInput'}, {'options': {'axes': [1]}}], + 'outputs': 'reduceMeanOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'reduceMeanOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedReduceMeanOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedReduceMeanOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.29411765933036804, -0.09019608050584793, + ], + 'descriptor': {shape: [2], dataType: 'float32'} + } + } + } + }, + { + 'name': 'quantized reduceSum', + 'graph': { + 'inputs': { + 'input': { + 'data': [ + 1.6811466217041016, 0.0479511022567749, 0.33355462551116943, + -0.1988269537687301, -0.0041167140007019, -0.0634240251779556, + ], + 'descriptor': {shape: [2, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'reduceSum', + 'arguments': [{'input': 'dequantizedInput'}, {'options': {'axes': [1]}}], + 'outputs': 'reduceSumOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'reduceSumOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedReduceSumOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedReduceSumOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.49803924560546875, -0.2666666805744171, + ], + 'descriptor': {shape: [2], dataType: 'float32'} + } + } + } + }, + { + 'name': 'quantized resample2d', + 'graph': { + 'inputs': { + 'input': { + 'data': [ + 1.6811466217041016, 0.0479511022567749, 0.33355462551116943, + -0.1988269537687301, -0.0041167140007019, -0.0634240251779556, + ], + 'descriptor': {shape: [1, 2, 3, 1], dataType: 'float32'}, + 'constant': false + }, + 'inputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'input'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'quantizedInput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInput'}, + {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'} + ], + 'outputs': 'dequantizedInput' + }, + { + 'name': 'resample2d', + 'arguments': [{'input': 'dequantizedInput'}, {'options': {'sizes': [4, 6], 'axes': [1, 2]}}], + 'outputs': 'resample2dOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'resample2dOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedResample2dOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedResample2dOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.49803924560546875, 0.49803924560546875, 0.0470588281750679, + 0.0470588281750679, 0.3333333432674408, 0.3333333432674408, + 0.49803924560546875, 0.49803924560546875, 0.0470588281750679, + 0.0470588281750679, 0.3333333432674408, 0.3333333432674408, + -0.20000001788139343, -0.20000001788139343, -0.003921568859368563, + -0.003921568859368563, -0.062745101749897, -0.062745101749897, + -0.20000001788139343, -0.20000001788139343, -0.003921568859368563, + -0.003921568859368563, -0.062745101749897, -0.062745101749897, + ], + 'descriptor': {shape: [1, 4, 6, 1], dataType: 'float32'} + } + } + } + }, ]; if (navigator.ml) { diff --git a/tests/wpt/tests/webnn/conformance_tests/subgraph.https.any.js b/tests/wpt/tests/webnn/conformance_tests/subgraph.https.any.js index 9b21d6e4f94..8a0b7faa92f 100644 --- a/tests/wpt/tests/webnn/conformance_tests/subgraph.https.any.js +++ b/tests/wpt/tests/webnn/conformance_tests/subgraph.https.any.js @@ -2523,6 +2523,45 @@ const subgraphTests = [ } } }, + { + 'name': 'float16 graph with float32 input and output', + 'graph': { + 'inputs': { + 'input': { + 'data': [1, 2, 3, 4], + 'descriptor': {shape: [4], dataType: 'float32'} + }, + 'weight': { + 'data': [2], + 'descriptor': {shape: [], dataType: 'float16'}, + 'constant': true + } + }, + 'operators': [ + { + 'name': 'cast', + 'arguments': [{'input': 'input'}, {'type': 'float16'}], + 'outputs': 'castOutput', + }, + { + 'name': 'add', + 'arguments': [{'a': 'castOutput'}, {'b': 'weight'}], + 'outputs': 'addOutput' + }, + { + 'name': 'cast', + 'arguments': [{'input': 'addOutput'}, {'type': 'float32'}], + 'outputs': 'output' + }, + ], + 'expectedOutputs': { + 'output': { + 'data': [3, 4, 5, 6], + 'descriptor': {shape: [4], dataType: 'float32'} + } + } + } + }, ]; if (navigator.ml) { diff --git a/tests/wpt/tests/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html b/tests/wpt/tests/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html index df4577c5614..1e148fe1b29 100644 --- a/tests/wpt/tests/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html +++ b/tests/wpt/tests/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html @@ -8,6 +8,7 @@ <script src='../../mediacapture-streams/permission-helper.js'></script> <script src="../../webrtc/RTCPeerConnection-helper.js"></script> <script src="../../service-workers/service-worker/resources/test-helpers.sub.js"></script> +<script src='RTCEncodedFrame-timestamps-helper.js'></script> <script> "use strict"; @@ -130,4 +131,56 @@ promise_test(async t => { return framesReceivedCorrectly; }, "Constructing audio frame with bad metadata argument before sending does not work"); + +promise_test(async t => { + const kCaptureTime = 12345; + const pc1 = new RTCPeerConnection({encodedInsertableStreams:true}); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection({encodedInsertableStreams:true}); + t.add_cleanup(() => pc2.close()); + + exchangeIceCandidates(pc1, pc2); + + let numFrames = 0; + let audioLevelRead = new Promise((resolve, reject) => { + pc2.ontrack = t.step_func(e => { + const receiverTransformer = new TransformStream({ + async transform(encodedFrame, controller) { + const metadata = encodedFrame.getMetadata(); + if (metadata.captureTime < kCaptureTime - 1 || metadata.captureTime > kCaptureTime + 1) { + reject("Unexpected captureTime"); + } + controller.enqueue(encodedFrame); + if (++numFrames == 10) + resolve(); + } + }); + const receiverStreams = e.receiver.createEncodedStreams(); + receiverStreams.readable + .pipeThrough(receiverTransformer) + .pipeTo(receiverStreams.writable); + }); + }); + + const stream = await navigator.mediaDevices.getUserMedia({audio:true}); + t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); + const sender = pc1.addTrack(stream.getAudioTracks()[0]); + const senderStreams = sender.createEncodedStreams(); + const senderTransformer = new TransformStream({ + async transform(encodedFrame, controller) { + let metadata = encodedFrame.getMetadata(); + metadata.captureTime = kCaptureTime; + controller.enqueue(new RTCEncodedAudioFrame(encodedFrame, {metadata})); + } + }); + senderStreams.readable + .pipeThrough(senderTransformer) + .pipeTo(senderStreams.writable); + + await addAbsCaptureTimeAndExchangeOffer(pc1, pc2); + await checkAbsCaptureTimeAndExchangeAnswer(pc1, pc2, true); + + await audioLevelRead; +}, 'Basic simulcast setup with three spatial layers'); + </script> diff --git a/tests/wpt/tests/webrtc/RTCConfiguration-iceServers.html b/tests/wpt/tests/webrtc/RTCConfiguration-iceServers.html index bc7831361ab..65a6015f52a 100644 --- a/tests/wpt/tests/webrtc/RTCConfiguration-iceServers.html +++ b/tests/wpt/tests/webrtc/RTCConfiguration-iceServers.html @@ -34,11 +34,14 @@ DOMString credential; }; */ + // RFC 8489 limits the length of the TURN username to 509 bytes: + // https://datatracker.ietf.org/doc/html/rfc8489#section-14.3 + const kUsernameOfMaxPermittedLength = 'a'.repeat(509); test(() => { const pc = new RTCPeerConnection(); assert_array_equals(pc.getConfiguration().iceServers, []); - }, 'new RTCPeerConnection() should have default configuration.iceServers of undefined'); + }, 'new RTCPeerConnection() should have default configuration.iceServers of []'); config_test(makePc => { makePc({}); @@ -181,6 +184,15 @@ }, `with one turns server, one turn server, username, credential should succeed`); + config_test(makePc => { + assert_equals(kUsernameOfMaxPermittedLength.length, 509); + const pc = makePc({ iceServers: [{ + urls: 'turn:turn.example.net', + username: kUsernameOfMaxPermittedLength, + credential: 'cred' + }] }); + }, `with a turn server and a username of 509 characters should succeed`); + /* 4.3.2. To set a configuration 11.4. If scheme name is turn or turns, and either of server.username or @@ -232,6 +244,16 @@ }] })); }, 'with turns server and only credential should throw InvalidAccessError'); + config_test(makePc => { + assert_equals(kUsernameOfMaxPermittedLength.length, 509); + assert_throws_dom('InvalidAccessError', () => + makePc({ iceServers: [{ + urls: 'turns:turn.example.net', + username: kUsernameOfMaxPermittedLength + 'a', + credential: 'cred' + }] })); + }, `with a turn server and a username of 510 characters throw InvalidAccessError`); + /* 4.3.2. To set a configuration 11.3. For each url in server.urls parse url and obtain scheme name. @@ -284,6 +306,8 @@ assert_throws_dom("SyntaxError", () => makePc({ iceServers: [{ urls: 'turn://example.org/foo?x=y' + // `username` and `credential` are not passed because the invalid url + // should be rejected before the check for those arguments. }] })); }, 'with invalid turn url should throw SyntaxError'); diff --git a/tests/wpt/tests/websockets/stream/tentative/remote-close.any.js b/tests/wpt/tests/websockets/stream/tentative/remote-close.any.js index b7fd321914a..c3e7ad5f9fb 100644 --- a/tests/wpt/tests/websockets/stream/tentative/remote-close.any.js +++ b/tests/wpt/tests/websockets/stream/tentative/remote-close.any.js @@ -48,7 +48,8 @@ promise_test(async t => { const closedError = await wss.closed.then(t.unreached_func('closed should reject'), e => e); assert_equals(closedError.constructor, WebSocketError, 'error should be WebSocketError'); assert_equals(closedError.closeCode, 4567, 'closeCode should be set'); - promise_rejects_js(t, WebSocketError, writePromise, 'write() should reject'); + await promise_rejects_dom( + t, 'InvalidStateError', writePromise, 'write() should reject'); }, 'close with unwritten data should not be considered clean'); promise_test(async t => { diff --git a/tests/wpt/tests/websockets/stream/tentative/write.any.js b/tests/wpt/tests/websockets/stream/tentative/write.any.js new file mode 100644 index 00000000000..43af7da614c --- /dev/null +++ b/tests/wpt/tests/websockets/stream/tentative/write.any.js @@ -0,0 +1,96 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: script=/common/gc.js +// META: global=window,worker +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +'use strict'; + +const GOODBYE_MESSAGE = 'Goodbye'; // Must match echo_exit_wsh.py + +// This message needs to be large enough that writing it cannot complete +// synchronously, and to fill up the TCP send buffer and any user agent internal +// send buffers so that the user agent has to receive the "Close" frame from the +// server before it can complete sending this message. +const BIG_MESSAGE_SIZE = 8 * 1024 * 1024; + +// Common setup used by two tests. Sends a "Goodbye" message to tell the server +// to close the WebSocket, and immediately afterwards a big message that cannot +// be completely sent before the connection closes. Waits for the "Goodbye" +// message to be sent and the connection to be closed before returning. `t` is +// the test object provided by promse_test. +async function sendGoodbyeThenBigMessage(t) { + const wss = new WebSocketStream(BASEURL + '/echo_exit'); + const { writable } = await wss.opened; + const writer = writable.getWriter(); + const bigMessage = new Uint8Array(BIG_MESSAGE_SIZE); + const goodbyePromise = writer.write(GOODBYE_MESSAGE); + const bigMessagePromise = writer.write(bigMessage); + await goodbyePromise; + // testharness.js doesn't know about WebSocketError yet. + await wss.closed.then( + t.unreached_func('closed promise should reject'), + e => assert_equals( + e.constructor, WebSocketError, + 'a WebSocketError should be thrown')); + return { writer, bigMessagePromise }; +} + +promise_test(async t => { + const { writer, bigMessagePromise } = await sendGoodbyeThenBigMessage(t); + await promise_rejects_dom( + t, 'InvalidStateError', bigMessagePromise, + 'write() should reject with an InvalidStateError'); + const invalidStateError = await bigMessagePromise.then( + t.unreached_func('write() promise should reject'), e => e); + await promise_rejects_exactly( + t, invalidStateError, writer.write('word'), + 'stream should be errored with same object'); +}, 'a write that was incomplete at close time should reject'); + +promise_test(async t => { + const { bigMessagePromise } = await sendGoodbyeThenBigMessage(t); + // For some reason 5 is the magic number that causes garbage collection to + // really really collect garbage. + for (let i = 0; i < 5; ++i) { + await garbageCollect(); + } + await promise_rejects_dom( + t, 'InvalidStateError', bigMessagePromise, + 'write() should reject with an InvalidStateError'); +}, 'garbage collection after close with a pending write promise should not ' + + 'crash'); + +promise_test(async t => { + const wss = new WebSocketStream(ECHOURL); + const { writable } = await wss.opened; + const writer = writable.getWriter(); + const cannotStringify = { toString() { return this; } }; + await promise_rejects_js( + t, TypeError, writer.write(cannotStringify), 'write() should reject'); +}, 'writing a value that cannot be stringified should cause a rejection'); + +promise_test(async t => { + const wss = new WebSocketStream(ECHOURL); + const { writable } = await wss.opened; + const writer = writable.getWriter(); + const buffer = new ArrayBuffer(1024, { maxByteLength: 65536 }); + await promise_rejects_js( + t, TypeError, writer.write(buffer), 'write() should reject'); +}, 'writing a resizable ArrayBuffer should be rejected'); + +promise_test(async t => { + const wss = new WebSocketStream(ECHOURL); + const { writable } = await wss.opened; + const writer = writable.getWriter(); + const memory = new WebAssembly.Memory({ + initial: 4096, + maximum: 65536, + shared: true, + }); + const view = new Uint8Array(memory.buffer); + await promise_rejects_js( + t, TypeError, writer.write(view), 'write() should reject'); +}, 'writing a view on a shared buffer should be rejected'); diff --git a/tests/wpt/tests/workers/WEB_FEATURES.yml b/tests/wpt/tests/workers/WEB_FEATURES.yml new file mode 100644 index 00000000000..1687ef742e2 --- /dev/null +++ b/tests/wpt/tests/workers/WEB_FEATURES.yml @@ -0,0 +1,6 @@ +features: +- name: ua-client-hints + files: + - WorkerNavigator_userAgentData.http.html + - WorkerNavigator_userAgentData.https.html + - WorkerNavigator_userAgentData.https.tentative.html diff --git a/tests/wpt/tests/workers/tentative/SharedWorker-extendedLifetime.html b/tests/wpt/tests/workers/tentative/SharedWorker-extendedLifetime.html new file mode 100644 index 00000000000..3c76eddd764 --- /dev/null +++ b/tests/wpt/tests/workers/tentative/SharedWorker-extendedLifetime.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<title>SharedWorker extendedLifetime</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script> + +let request_id = 0; + +const connectToSharedWorker = async () => { + await window.pageShowPromise; + window.worker = new SharedWorker( + '/workers/tentative/resources/shared-worker-memory.js', + {extendedLifetime: true}); + worker.port.start(); +}; + +const postAndWait = async (data) => { + return new Promise(resolve => { + const listener = event => { + if (event.data.reqid !== data.reqid) { + return; + } + worker.port.removeEventListener('message', listener); + resolve(event.data); + }; + worker.port.addEventListener('message', listener); + worker.port.postMessage(data); + }); +}; + +promise_test(async t => { + // SharedWorker is started with the extendedLifetime option. + // random message is stored there, which can be read later. + const uuid = token(); + const ctx = new RemoteContext(token()); + const popup = window.open(remoteExecutorUrl(ctx.context_id)); + await ctx.execute_script(connectToSharedWorker); + const popup_response = await ctx.execute_script(postAndWait, [{ + reqid: request_id++, + op: 'store', + data: uuid, + }]); + assert_equals(popup_response.status, 'OK'); + popup.close(); + + // Wait for a second. + await new Promise(resolve => setTimeout(resolve, 1)); + + const ctx2 = new RemoteContext(token()); + const popup2 = window.open(remoteExecutorUrl(ctx2.context_id)); + await ctx2.execute_script(connectToSharedWorker); + const popup2_response = await ctx2.execute_script(postAndWait, [{ + reqid: request_id++, + op: 'load', + }]); + assert_equals(popup2_response.status, 'OK'); + assert_equals(popup2_response.data, uuid); +}, "SharedWorker lifetime should be extended with extendedLifetime"); +</script> diff --git a/tests/wpt/tests/workers/tentative/resources/shared-worker-memory.js b/tests/wpt/tests/workers/tentative/resources/shared-worker-memory.js new file mode 100644 index 00000000000..b1504f38c50 --- /dev/null +++ b/tests/wpt/tests/workers/tentative/resources/shared-worker-memory.js @@ -0,0 +1,30 @@ +'use strict'; + +let stored_data = null; + +function processMessage(e) { + function respond(data) { + e.currentTarget.postMessage(Object.assign(data, {reqid: e.data.reqid})); + } + + switch (e.data.op) { + case 'load': { + respond({ack: 'load', status: 'OK', data: stored_data}); + break; + } + case 'store': { + try { + stored_data = e.data.data + } catch (err) { + respond({ack: 'store', status: 'ERROR', error: err.name}); + return; + } + respond({ack: 'store', status: 'OK'}); + break; + } + } +} + +self.addEventListener('connect', e => { + e.ports[0].onmessage = processMessage; +}); diff --git a/tests/wpt/webgl/meta/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html.ini b/tests/wpt/webgl/meta/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html.ini index 5b9d4a0e1b9..f8ab654ff94 100644 --- a/tests/wpt/webgl/meta/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html.ini +++ b/tests/wpt/webgl/meta/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html.ini @@ -3,9 +3,3 @@ expected: TIMEOUT [Overall test] expected: NOTRUN - - [WebGL test #0] - expected: FAIL - - [WebGL test #1] - expected: FAIL diff --git a/tests/wpt/webgl/meta/conformance/textures/misc/texture-upload-size.html.ini b/tests/wpt/webgl/meta/conformance/textures/misc/texture-upload-size.html.ini index 435cfbe0d5c..e9f1c0ae3f3 100644 --- a/tests/wpt/webgl/meta/conformance/textures/misc/texture-upload-size.html.ini +++ b/tests/wpt/webgl/meta/conformance/textures/misc/texture-upload-size.html.ini @@ -13,3 +13,75 @@ [WebGL test #588] expected: FAIL + + [WebGL test #53] + expected: FAIL + + [WebGL test #55] + expected: FAIL + + [WebGL test #57] + expected: FAIL + + [WebGL test #59] + expected: FAIL + + [WebGL test #69] + expected: FAIL + + [WebGL test #71] + expected: FAIL + + [WebGL test #73] + expected: FAIL + + [WebGL test #75] + expected: FAIL + + [WebGL test #85] + expected: FAIL + + [WebGL test #87] + expected: FAIL + + [WebGL test #89] + expected: FAIL + + [WebGL test #91] + expected: FAIL + + [WebGL test #101] + expected: FAIL + + [WebGL test #103] + expected: FAIL + + [WebGL test #105] + expected: FAIL + + [WebGL test #107] + expected: FAIL + + [WebGL test #117] + expected: FAIL + + [WebGL test #119] + expected: FAIL + + [WebGL test #121] + expected: FAIL + + [WebGL test #123] + expected: FAIL + + [WebGL test #133] + expected: FAIL + + [WebGL test #135] + expected: FAIL + + [WebGL test #137] + expected: FAIL + + [WebGL test #139] + expected: FAIL |